Vue第六章Vue-route/第七章UI组件库/第八章Vue3/第九章其他composition

第六章 Vue-route

只有配置路由规则的时候是routes 其他都是router

1.route的简介

1.它是Vue的一个插件库,专门用来实现SPA应用的
spa (single page web application)单页面应用

2.SPA应用的理解
它是一个单页面应用
他只有一个index页面
在页面中点击导航链接不会刷新,只会局部更新
通过AJAX请求获取数据

3.什么是路由
路由就是一组映射关系 key - value的

key为路径 value可以是组件或者方法

后端路由就是匹配方法
前端路由就是匹配组件

2.路由的基本使用

1.因为路由是一个插件 ,需要安装使用

npm i vue-router@3

2.引入并且使用Vue的路由器
那么在vm上会多出来一个配置 router:

// 映入Vue的路由器
import vueRouter from 'vue-router'
// 使用路由器插件
Vue.use(vueRouter)

3.在src/router—index.js 配置路由器router

// 引入vue-router  它得到的是一个构造函数
import vueRouter from 'vue-router'

import About from '../components/About'
import Home from '../components/Home'

// 暴露配置的路由器  到vm中
 export default new vueRouter({
        // 在这个构造函数中配置一个 routes
        routes: [  // 配置一个一个对象  中包含 path路由key 和 component 路由value
            {   
                path:'/about', 
                component:About
            },
            {
                path:'/home',
                component:Home
            }
        ]
    })

4.在main.js的vm中 引入index.js 配置 router

import router  from './router'

new Vue({
    el:'#app',
    render: h =>h(App),  // 会覆盖 index上面的 <div id="app"></div>
    router   // 配置  router 
})

5.在需要路由的地方 用 <router-link 标签 to 到路径 这个标签会自动转化为a标签 实现路由key的切换

          <!-- router-link这个标签 会自动转化为a标签 -->
          <router-link class="list-group-item" active-class="active" to="/about">About</router-link>
          <router-link class="list-group-item" active-class="active" to="/home">Home</router-link>

6.在要使用到路由变化组件的地方 使用 <router-view 来站位

      <router-view></router-view>

3.Vue-router的几个注意点

1.一般会多写一个文件夹放路由组件,而一般组件会放在components上

2.切换掉的路由默认是被销毁了

3.被router管理的组件上,会多出一个$route属性和 $ router属性
route属性是一个组件自己的路由信息,而router是全部路由的信息

4.vue-router的多级路由 使用children[]来实现任意多级嵌套

1.需要在一个路由对象下使用children[{},{}]继续配置子路由 但是不用加/了

        routes: [  // 配置一个一个对象  中包含 path路由key 和 component 路由value
            {   
                path:'/about', 
                component:About
            },
            {
                path:'/home',
                component:Home,
                // 多级路由 可以使用children配置一个对象数组
                children:[
                    {
                        path:'news',
                        component:News
                    },

                    {
                        path:'message',
                        component:Message
                    }
                ]
            }
        ]

2.在router-link的时候 to的地址写全。还是用router-view站位

        <ul class="nav nav-tabs">
          <li>
            <!-- <a class="list-group-item" href="./home-news.html">News</a> -->
            <!-- 使用router-link 代替a标签 -->
            <router-link class="list-group-item" active-class="active" to="/home/news">News</router-link>
            
          </li>
          <li>
            <!-- <a class="list-group-item active" href="./home-message.html">Message</a> -->
            <router-link class="list-group-item" active-class="active" to="/home/message">Message</router-link>
          </li>
        </ul>
        <router-view></router-view>

5.路由之间query传递参数,参数放在$route.query上(一)

1.在to路径上传递参数

          <ul>
            <li v-for="m in messages" :key="m.id">
               
                <!-- 使用query类型来传递参数  就是路径后面?传参 -->
              <router-link to="/home/message/list?name=战三&age=20">{{ m.title }}</router-link>&nbsp;&nbsp; 
           

   <!-- 如果要使用变量传递参数  就要用  :绑定为js表达式  在用``中的${使用变量}-->
               <router-link :to="`/home/message/list?id=${m.id}&title=${m.title}`">{{ m.title }}</router-link>&nbsp;&nbsp;
                

<!-- 使用对象传递参数:to -->
                <router-link :to="{
                    path:'/home/message/list',
                    query:{
                        id:m.id,
                        title:m.title
                    }
                }">{{ m.title }}</router-link>&nbsp;&nbsp;
            </li>

2.参数被传递vc.$route.query上

6.路由命名简化复杂路径

1.在routes中 路由配置多一个 name配置项 配置名字

                        children:[
                            {
                                name:'liebiao',
                                path:'list',
                                component:List
                            }
                        ]

2.在使用to的时候 要成对象形式 :to{name:‘name’}

                <router-link :to="{
                    // path:'/home/message/list',
                    name:'liebiao',   // 使用name来代替路径
                    query:{
                        id:m.id,
                        title:m.title
                    }
                }">{{ m.title }}</router-link>&nbsp;&nbsp;

7.路由之间传递参数params,to对象的形式必须是name

1.在routes中配置的时候,需要在path后面接收参数 /a/:id/:title

   children:[
       {
          name:'liebiao',
           path:'list/:id/:title',  // 使用params传递参数 这里站位符指定参数名
         component:List
              }
         ]

2.在to传递参数的时候 直接写在路径上那么可以直接传递值 /a/0/fa

           <!-- 如果要使用变量传递参数  就要用  :绑定为js表达式  在用``中的${使用变量} 
                params 传递参数 直接 //-->
              <router-link :to="`/home/message/list/${m.id}/${m.title}`">{{ m.title }}</router-link>&nbsp;&nbsp;

如果是to对象 那么它必须是name 和使用params对象传递参数

                <router-link :to="{
                    // path:'/home/message/list',
                    name:'liebiao',   // 使用name来代替路径
                    params:{     // 使用params 那么不能是path 必须是name
                        id:m.id,
                        title:m.title
                    }
                }">{{ m.title }}</router-link>&nbsp;&nbsp; 

3.使用$route.params.参数名 来访问参数

8.路由的props配置 简化组件参数的接收

在routes 中新增一个props配置项 他有三种写法

  1. 对象写法{} ,他的keyvalue都会以props的形式传递给组件
                        children:[
                            {
                                name:'liebiao',
                                path:'list/:id/:title',  // 使用params传递参数 这里站位符指定参数名
                                component:List,
                                props:{id:1,title:'你好'}   //对象写法{}  ,他的key-value都会以props的形式传递给组件
                            }
                        ]

2.props:true // 布尔值 为true的时候 那么这个params参数 会议props的形式传递给组件

                <router-link :to="{
                    // path:'/home/message/list',
                    name:'liebiao',   // 使用name来代替路径
                    params:{     // 使用params 那么不能是path 必须是name
                        id:m.id,
                        title:m.title
                    }
                }">{{ m.title }}</router-link>&nbsp;&nbsp;

3.函数的形式,他会收到一个route对象 返回一个对象 这个对象会以props的形式传递给组件

                                props($route){
                                    return {
                                        id:$route.params.id,
                                        title:$route.params.title
                                    }
                                }
注意使用params传递参数的时候 在path上要写:/id站位参数

9.浏览器历史记录模式 push replace(替换)

1.浏览器是以栈的方式去存储 url资源页面
2.默认的router-link 是以push的形式跳转页面 ,也就是说往浏览器历史记录中压栈,然后指针指向栈顶元素,可以回退

3.在route-link中开启replace模式 那么他就会替换栈顶元素 ,而不是压栈

  <router-link :replace="true"

10.编程式路由导航 $router.push()/replace()

1.push方法和replace方法

            methods:{
                pushShow(m){
                    // 编程式的路由导航  由$router原型对象上的东西 push 、replace
                    this.$router.push({
                        // 这个对象中的配置和to中的一样
                        name:'liebiao',
                       // query:{},
                        params:{
                            id:m.id,
                            title:m.title  
                        }
                    })
                },
                replaceShow(m){
                    console.log(this.$router)
                    // replace是替换栈顶页面
                    this.$router.replace({
                    //  path:'',
                        name:'liebiao',
                        params:{
                            id:m.id,
                            title:m.title  
                        }
                    })
                }
            }

2.back方法前一个页面 forward 前进一个页面 to正数前进几个 负数后退几个

        methods:{
          qianjin(){
            this.$router.forward() // 后退页面
          },
          houtui(){
            this.$router.back()  // 前进页面
          },
          tiao(){
            this.$router.go(3) // 正数 往前跳几个  负数 往后跳几个
          }
        }

11.缓存路由组件,让他们切换时不被销毁

1.可以利用 《keep-alive include=‘组件名’》

        <!-- 这里包含两个组件 ,一个news 和 一个message  要想在切换的时候不被销毁 那么就要加上 keep-alive -->
        <keep-alive include="News">
          <!-- 默认不写include 的话 那么就是包裹全部 全部都缓存 -->
          <router-view></router-view>
        </keep-alive>

2.多个的话 :keep-alive="[‘news’,‘message’]

12.两个新的生命周期,路由组件专属activated、deactivated

1.activated钩子 ,在组件被激活的时候被调动

        activated(){
                // 路由组件被激活的时候被调用
                // 路由组件被激活了
                console.log('路由组件激活')
               this.dd =  setInterval(()=>{
                        this.options -= 0.01;
                        if(this.options <= 0) this.options = 1
                },16)
        },

2.deactivated钩子 ,组件在被失活的时候被调用

        deactivated(){
                // 路由组失活的时候被调用
                console.log('路由组件失活')
                clearInterval(this.dd)
        }

3.nextTick()这个钩子是 下一次更新dom元素后被调用


```java
          // 获取焦点   这个nexttick 在下一次更新完成DOM元素后被调用
          this.$nextTick(function(){
            this.$refs.editFocus.focus()
          })

13.全局前置路由守卫(拦截器)

to 和 from 都是一个一个route

  1. beforeEach((to,from,next)=>{
    }
    )
const rou = new VueRouter({})
    // 给路由器配置全局前置路由守卫  它是初始化的时候会执行一次  还有,每次路由切换的时候会执行
    // to 是到哪去的路由详情  from是来自哪里  next 放行  如果没有被放行那么路径也不会发生改变
    rou.beforeEach((to,from,next)=>{
        console.log(to,from)
        if(to.name !== 'xinwen'){
            next()  // 放行
        }
    })

    export default rou

14.路由中配置 元数据 meta:{}

 meta:{title:'关于'}  // 这个是在路由中配置自己的属性  通过 $route.meta.xxx拿取

15.全局后置路由守卫 afterEach(to,from)


    // 全局后置路由守卫  初始化的时候被调用, 路由切换之后被调用
    rou.afterEach((to,from)=>{
        console.log(to,from)
        document.title = to.meta.title
    })

16.独享路由守卫 在routes中配置 beforeEnter()

独享路由守卫只有前置没有后置

如果配置了全局路由守卫 也配置了独享路由守卫 那么 先执行全局

                // 多级路由 可以使用children配置一个对象数组
                children:[
                    {
                        name:'xinwen',
                        path:'news',
                        component:News,
                        meta:{title:'新闻'},
                        beforeEnter(to,from,next){
                            console.log("独享的",to,from)
                            if(to.name !== 'xinwen'){
                                next()  // 放行
                            }else{
                                alert("你不能访问")
                            }
                        }
                    },

17.组件内路由守卫

1.在定义组件的时候在对象中传入 beforeRouteEnter((to,from,next){
// 这个是 通过路由规则 进入组件之前触发
})

export default {
      name:'About',
      mounted(){
        console.log(this)
      },
      // 直接在组件内配置路由守卫
      beforeRouteEnter (to, from, next) {
        console.log("我是组件内路由守卫  在通过路由规则 进入这个组件之前被调用")
        next() // 放行
      },
      beforeRouteLeave (to, from, next) {
        console.log("我是组件内路由守卫, 在通过路由规则离开之前被调用")
        next() // 放行
      }
}

2.beforeRouteLeave 通过路由规则离开组件之前触发

18.路由器的两种工作模式history、hash

1.首先默认采用的是hash的模式,在这种模式下url#及后面的路径不会随着http请求携带给服务器

2.history模式,这种模式下是没有#号,它会把全部的url携带给服务器

配置:
在new VueRouter({
配置
mode:‘history/hash’,
routes:[{}]
})

3.使用 npm run build,会把项目构建,把Vue文件给转化为html、js、css文件,然后把它放在服务器上运行

第七章:Vue UI组件库

1. 移动端常用 UI 组件库

  1. Vant https://youzan.github.io/vant
  2. Cube UI https://didi.github.io/cube-ui
  3. Mint UI http://mint-ui.github.io

2. PC 端常用 UI 组件库

  1. Element UI https://element.eleme.cn
  2. IView UI https://www.iviewui.com

3.elementUI 的基本使用

1.安装插件

npm i element-ui -S

2.完整引入 在main.js中引入

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

3.参照elementUI的组件文档选取组件

完整引入太大了 可以用到什么标签就引入什么 按需引入
1.首先,安装 babel-plugin-component:

npm install babel-plugin-component -D

2.将babel.config.js 中的配置 合并为

{
  "presets": [["@babel/preset-env", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

3.在 main.js 中写入以下内容:

import { Button, Select } from 'element-ui';

  全局注册组件   组件名
Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
/* 或写为
 * Vue.use(Button)
 * Vue.use(Select)
 */

第八章 Vue3 组件中的模板结构可以没有根标签

构建工具vite 它是先启动服务,再按需加载资源,(快速冷启动)
而传统的是先全部加载完成资源 在启动服务

1.分析工程结构

1.在main.js中

// 引入一个名为createApp的工厂函数  创建对象不用new
import { createApp } from 'vue'

createApp(App).mount('#app')

createApp(App) 他会返回一个App实例对象,它是vm的精简版

mount()是挂载某个组件  而 unmount()是取消挂载

2.安装Vue3的开发者工具看视频P140

3.初识setup (所有composition API的表演舞台)

let 表示一个可变的变量 const表示一个不可变的

1.在Vue3中所有的data,methods,computed等都是放在setup中

2.setup的返回值可以是对象也可以是渲染函数
对象:那么在模板中可以直接使用对象中的东西

  setup(){
    let name = 'zhansgan'; // let 表示一个可变的变量  const表示一个不可变的
    let age = 20;
    let sex = '男';

    function helloVue3(){
      // ``号 配合${变量}取值
        alert(`欢迎学习vue3${name}${age}${sex}`)
    }
    // 2.setup的返回值可以是对象也可以是渲染函数
    //   对象:那么在模板中可以直接使用对象中的东西
    //   渲染函数:
    return {   
      name:name,
      age,
      sex,
      helloVue3
    }
  //  return ()=>{return h('h1','欢迎学习·')}
  }

渲染函数:

import {h} from 'vue'
setup(){
	// 数据 函数 计算属性  watch等
	return ()=>{return h('h1','欢迎学习·')}
}

3.注意Vue2的data,methods,computed等中可以访问setup返回的东西
而setup中不能访问Vue2中的东西(尽量不要混写)

如果混写重名了 那么以Vue3的为准

4.ref函数 处理基本数据类型的函数(响应式)

原来的在标签中的ref属性的话 它是id的替代者,它主要用来给元素打标识,通过this.$refs.名字得到

1.引入ref函数

import {ref} from 'vue'

2.用ref函数包裹基本数据类型

    let name = ref('zhansgan'); // let 表示一个可变的变量  const表示一个不可变的
    let age = ref(20);
    let sex = ref('男');

那么ref的返回值就是一个refimpl 引用实例对象 ,要是想要修改一个值Vue监测到那么就要通过这个对象的value来修改

  // 1.在Vue3中所有的data,methods,computed等都是放在setup中
  setup(){// 所有compositionAPI的表演舞台 
    let name = ref('zhansgan'); // let 表示一个可变的变量  const表示一个不可变的
    let age = ref(20);
    let sex = ref('男');
    function update(){
      // Vue监测到那么就要通过这个对象的value来修改
      console.log(name)
      name.value = '张三';
      age.value= 33;
      sex.value = '女';
      
    }

3.在模板中还是可以通过属性名直接访问,因为Vue3直接帮我们.value了

    <h1>姓名{{ name }}</h1>
    <h2>年龄{{ age }}</h2>
    <h2>性别{{ sex }}</h2>

5.ref函数 处理对象类型的数据

这个对象是 refimpl 引用实例
    let obj = ref({
      // 用ref包裹住一个对象
      name:'私立',
      age:'20'
    })
这个对象.value这个value是 proxy来包裹住的
      console.log(obj.value)     //  
      obj.value.age=30

使用的时候还是不用加value
    <!-- 访问的时候也不用加value -->
    <h1>{{ obj.age }}</h1>   

基本数据类型的响应是靠defineproperty 的setget方法来实现的

而对象数据类型的响应靠的是 Vue3.0中的一个函数reactive (这个函数中用到了proxy)

6.reactive函数 对象/数据的响应式数据定义 不用value

定义响应式的数据是深层次的

1.const proxy = reactive(源对象) 返回代理对象,不用点value直接修改

    let obj = reactive({
    
      name:'私立',
      age:'20'
    })

    // Vue3中操作数组直接操作元素也可以是响应式的
    let arr = reactive(['1','2','3'])


      console.log(obj)    //  这个obj就是proxy  === ref的 obj.value
     obj.age=333  // 数据修改不用value
     arr[0] = '8'

7.回顾Vue2的数据监测原理

1.对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)
2.数组类型:它是通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。

缺点:
新增属性、删除属性, 界面不会更新。
解决:
1.通过this.$set(哪个对象,属性/数组下标,修改的值)
this. $delete(哪个对象,属性/数据下标)
缺点2:
直接通过下标修改数组, 界面不会自动更新。
解决:
通过this. $set(哪个对象,属性/数组下标,修改的值)
或者用Vue包裹住的方法来操作数据

8.Vue3的响应式原理(proxy构造函数)

使用proxy(person,// 第一个参数是代理哪个对象 ,{})

  1. get(target,propName) 当有人想要获取 p中的属性时调用
    target 是代理对象的源对象 propName是 操作的属性名
  2. set(target,propName,value) set方法是 有人修改p的属性 或者是给p新增属性的时候会调用
  3. deleteProperty(target,propName) 有人 删除p中的一个属性的时候会调用
       const p= new Proxy(person,{// 第一个参数是代理哪个对象  
            // 当有人想要获取 p中的属性时调用
            get(target,propName){
                // target 是代理对象的源对象   propName是 操作的属性名
                console.log("get中的",target,propName)
                return target[propName]
            },
            // set方法是 有人修改p的属性 或者是给p新增属性的时候会调用
            set(target,propName,value){
                // target 是代理对象的源对象   propName是 操作的属性名  value是修改值
                console.log('我监测到了  我要去刷新页面了')
                target[propName] = value;
            },
            // deleteproperty方法是 有人 删除p中的一个属性的时候会调用
            deleteProperty(target,propName){
             return  delete target[propName]
            }
       })  
Reflect反射 来操作属性
       const p= new Proxy(person,{// 第一个参数是代理哪个对象  
            // 当有人想要获取 p中的属性时调用
            get(target,propName){
            
                console.log("get中的",target,propName)
                return Reflect.get(target,propName)   // 得到这个对象中的这个方法
            },
         
            set(target,propName,value){
            
                console.log('我监测到了  我要去刷新页面了')
                Reflect.set(target,propName,value)  //修改这个对象的这个属性的值
            },
        
            deleteProperty(target,propName){
             return  Reflect.deleteProperty(target,propName) // 删除这个对象中的这个属性
            }

            // 另外这个Reflect中也有defineproperty这个方法  和object中的一样
            //Reflect.defineProperty()
       })  

9.Vue3 setup的两个参数

setup的执行是在beforeCreate钩子函数之前的 并且 setup中的this是未定义的

首先$attrs 是没有用props接收的参数就会放在这里
$slots 这个是组件的插槽

  props:['msg','x'],
  emits:['hello'],
  setup(props,context){
    // console.log(props.x)   // 这个参数是 props 传递的参数
    console.log(context.attrs)  //context上下文 他有attrs 就是没有用props接收的参数都在attrs中
    console.log(context.emit)  // 这个是用来触发事件的
    console.log(context.slots)  // 这个是这个组件传递的插槽
<template>
  <!-- Vue3中可以没有 根标签 -->
<div>
    <h1>姓名{{ obj.name }}</h1>
    <h2>年龄{{ obj.age }}</h2>
    <slot name="s"></slot>
    <button @click="dian">点我触发hello事件</button>
</div>
</template>

<script>
// 引入reactive函数
import {reactive} from 'vue'
export default {
  name: 'Demo',
  props:['msg','x'],  // 组件内部要接收  声明接收
  emits:['hello'],
  setup(props,context){
    // console.log(props.x)    // 这个参数是 使用props声明接收了的属性
    console.log(context.attrs)  //context上下文 他有attrs 就是没有用props接收的参数都在attrs中
    console.log(context.emit)  // 这个是用来触发事件的
    console.log(context.slots)    // 收到插槽的内容
    let obj = reactive({
      name:'私立',
      age:'20'
    })

    function dian(){
      context.emit('hello',999)
    }

    return {   
      obj,
      dian
    }
  //  return ()=>{return h('h1','欢迎学习·')}
  }
}
</script>

<style>

</style>

10.Vue3的computed 组合pai

import {reactive,computed} from 'vue'


 // 定义属性也是通过composition组合api来实现的  这个是简写形式
    // obj.fullName = computed(()=>{
    //   return obj.firstName + '-' + obj.lastName
    // })

    计算属性名 = computed({
      get(){
        return obj.firstName + '-' + obj.lastName
      },
      set(value){
        let a =   value.split('-')
        obj.firstName = a[0]
        obj.lastName = a[1]
      }
    })

11.Vue3的watch

注意 watch只能监视 ref属性、reactive对象、数组监视对象默认就有深度监视
    1.监视ref基本数据类型 的一个数据   参数一 监视的属性 参数二 回调函数  参数三 配置参数
    watch(sum , (newvalue,oldvalue)=>{
        console.log('sum改变咯',newvalue,oldvalue)
    },{immediate:true})
    2. 监视ref多个数据用数组
    watch([sum,name],(new1,old1)=>{
      console.log("sum或者name改变咯",new1,old1)
    },{immediate:true})

    3.监视reactive 对象 的问题
    问题一: newvalue和oldvalue都是 新的数据
    问题而: deep深度监视 配置失效
    watch(obj,(new1,old1)=>{
      console.log('reactive监视的对象改变了',new1,old1)
    },{deep:false})

    4. 监视对象中的一个属性的话 那么要写成函数的返回值 一个ref
    注意 :: watch只能监视 ref、reactive对象、数组
    watch(()=>{return obj.sex},(new1,old1)=>{
      console.log("我只要监视对象中的一个属性",new1,old1)
    })

    5.监视对象中的多个 属性  通过返回一个数组的形式  
    watch(()=>{return [obj.sex,obj.age]},(new1,old1)=>{
      console.log("监视对象中的多个属性",new1,old1)
    })
    或者写成多个函数
    watch([()=>{return obj.sex},()=>{return obj.age}],(new1,old1)=>{
      console.log("监视对象中的多个属性",new1,old1)
    })

    // 如果watch监视的是一个ref包裹住的对象 那么 可以使用.value 或者开启深度监视
    // 如果不点value 那么 他监视的是refimpl  当修改的是对象中的属性的时候 使用Proxy包裹住的 要开启深度监视
    watch(obj.value,(new1,old1)=>{
        
     },{deep:true})

12.watchEffect函数 组合api

watchEffect函数 监视的是这个回调函数中所用到的数据(发生改变就会执行) 初始化就会执行一次

有点像computed 所依赖的属性发生改变就用到 但是它注重的值返回值
watchEffect注重的是过程 回调函数的过程

    // watchEffect函数 监视的是这个回调函数中所用到的数据  初始化就会执行一次
    // 不管有多深都可以
    watchEffect(()=>{
      const a = sum.value  
      console.log("我先执行一下")
    })

13.Vue2生命周期和Vue3的生命周期对比

Vue2生命周期

在这里插入图片描述

此图片来自
在这里插入图片描述
此图片来自
在这里插入图片描述
Vue2 他不会先检查这个 el是否有就会执行掉 beforeCreate,和Created钩子,再会检查

而Vue3 会CreateApp(App).mount(“#app”)先执行 ,后面就不会判断有没有el了

Vue3的最后阶段变为了 beforeUnMount写在之前 和 unMount卸载之前
但是写在setup里面,就要先引入组合API 才能使用 而 BeforeCreate和Create都变为了setup 其他的钩子函数前面都加上on

  beforeCreate() {
    console.log("----我beforeCreate 数据还没有 数据监测也没有")
  },
  created(){
    console.log("----我created 数据代理数据监测都有了")
  },
  beforeMount(){
    console.log("-----我 beforeMount还没有完成挂载 是未经编译的DOM结构" )
  },
  mounted(){
    console.log("-----我mounted 已经挂载完成")
  },
  beforeUpdate(){
    console.log("-----我 beforeUpdate数据更新到页面之前  数据已经改变但是 页面没有修改")
  },
  updated(){
    console.log("-----我updated数据和页面都修改了")
  },
  beforeUnmount(){
    console.log("---- 我beforeUnmount是卸载之前要关闭一些东西 自定义事件啊 消息的订阅预发布啊")
  },
  unmounted(){
    console.log("-----我unmounted是卸载完成")
  }

而在setup中写的话
import {onMounted} from 'vue'
 setup(){
    onMounted(()=>{
      console.log("-----onMounted 已经挂载完成")
    })
}
 

14.Vue3中的hook函数 它是对setup中的组合API进行封装

hook本质上是一个函数,它是对setup的组合API进行了封装,类似于vue2.x中的mixin

hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。

1.在src文件目录下新建 hooks文件下,下面放封装的js文件,一般以useXXX.js

// 这个函数的功能就是 给一个窗口绑定点击事件 并且返回鼠标点击的坐标
import {reactive,onMounted,onBeforeUnmount} from 'vue'
// 封装组合API
export default function(){
    
    let point = reactive({
        x:0,
        y:0
      })
      function getXY(e){
        console.log(e.pageX,e.pageY)
          point.x = e.pageX
          point.y = e.pageY
        }   
  
      //在这个组件挂载的时候就给绑定事件
      onMounted(()=>{
        // 这个是给一个窗口绑定事件  后面是事件函数
        window.addEventListener('click',getXY)
      })
      // 组件被卸载时解绑事件
      onBeforeUnmount(()=>{
        // 这个是移除事件  后面也是事件函数
        window.removeEventListener('click',getXY)
      })
      return point
}

2.把要封装的 compositionAPI 做成一个函数返回数据,并且暴露

3.在要使用到这个函数的地方引入 ,并且接收到返回值

// 引入hook函数
import usePoint1 from '../hooks/usePoint'

  const point = usePoint1() // 调用函数的到返回值  返回出去使用

15.Vue3中的toRef&toRefs

toref主要是生成一个refimp对象,它是对象中的某一个属性,value以代理的方式联动

    // toRef函数 代理对象 代理对象中的一个属性  
    // 第一个参数是代理哪个对象  第二个参数是 对象中的哪一个属性
    const sex=toRef(obj,'sex')

torefs的话是生成一个对象的第一层属性的代理Proxy

 toRefs函数 处理对象的所有第一层属性
  const a=toRefs(obj)
      ...toRefs(obj),  // ... 是把这个对象的属性摊开放在另一个对象中

应用:想要把一个对象的某些属性提供给外部使用,而不会丢失响应式,数据也是一致
在这里插入图片描述

第九章 Vue3的其他compositionAPI

1.shallowReactive和ShallowRef (Shallow浅层的)

shallowReactive:它只会监测对象的第一层属性的变化

shallowRef:它不会监测对象的属性变化(数组也不会),因为Value没有用proxy,它适用于对象属性值不变,整个对象替换的

    // shallowReactive:它只会监测对象的第一层属性的变化 后面的层数就没有用proxy了
    let obj = shallowReactive({
      sex:'男',
      age:20,
      job:{
        slary:20
      }
    })
    // shallowRef他只会监测基本数据类型 而对象类型不会用Proxy
    let x =shallowRef({y:0})

2.shallowReadonly(浅只读第一层)和Readonly(深只读)

    let x = ref(0)
    // shallowReactive:它只会监测对象的第一层属性的变化 后面的层数就没有用proxy了
    let obj = reactive({
      sex:'男',
      age:20,
      job:{
        slary:20
      }
    })
    // readonly这个包裹一个数据 那么这个数据就是只可读的 不能被修改
    x = readonly(x)
    // shallowReadonly 包裹一个数据  如果这个数据是对象的话 那么只会有第一层只可读  后面的层是响应式的
    obj = shallowReadonly(obj)

3.toRaw(响-原)和markRaw(标记为原始)组合API

toRaw:把reactive的数据变为原始数据, Vue3不会监测响应
const yuanshi = toRaw(obj)

    // toRaw 把reactive的数据变为原始数据 Vue3不会监测响应  
    // 但是他的改变实际上这个obj也会改变  只要以后这个obj改变的话 那么就会响应之前的修改
    const yuanshi = toRaw(obj)

markRaw:把这个对象标记为一个原始对象 ,那么这个对象不会在是响应式的 基本数据类型的话就改变
markRaw(car)

    function addCar(){
      // 这样往reactive的对象 那么这个对象也是响应式的
      let car = {name:'奔驰',price:40}  
      // markRaw标记为对象
      markRaw(car)
      console.log(car)  // 被markRaw修饰的话 那么就是Object的 不是proxy的
      obj.car = car
    }
toRaw:
    作用:将一个由reactive生成的响应式对象转为普通对象。
    使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。
markRaw:
    作用:标记一个对象,使其永远不会再成为响应式对象。
    应用场景:
        有些值不应被设置为响应式的,例如复杂的第三方类库等。
        当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。

4.customRef 定做的Ref

customRef是可以自定义一个ref,并对其依赖项跟踪和更新触发进行显式控制。
案例

    setup(){
      let times
      // 2.创建函数的实现 并且再里面使用customRef进行 自定义控制  
      // customRef 自定义一个ref 并对其依赖项追踪track和数据更新触发trigger进行显示控制
      function myRef(value){
        // 3.customRef的使用 ,需要传递一个函数 并且返回一个对象,里面会包括getset方法 
        // get 在模板中读取get返回值的是时候被调用  set修改value的时候调用
         return customRef((track,trigger)=>{
          // track追踪依赖数据的改变get  trigger触发模板重新解析
          return {
            get(){
              console.log("get方法调用返回value",value)
              track() // 追踪value的改变
              return value;
            },
            set(newvalue){
              console.log("set方法被调用新值是",newvalue)
              // 因为是读取返回的get中的value ,所以要修改value 不过要触发模板的重新解析去读取value
              clearTimeout(times) // 清除上一个定时器 只留下最后一个  防抖
              times=setTimeout(()=>{  //过500毫秒去触发更新
              value = newvalue
              trigger()//触发模板的重新解析去读取value
             },500)
            }
          }
        })
      }
      // 1.先自定义一个函数,传递需要的参数
      let keyward = myRef('hello')

5.provide与inject用于父与后代组件之间传递数据

1.在父组件中使用provide(“参数名”,数据)来传递

    setup(){
      let car = reactive({name:'奔驰',price:'40W'})
      provide("car",car)  //在父组件中 提供参数名 数据
      return {
          ...toRefs(car) // 对象摊开
      }
    }

2.在任意的后代组件中使用inject(“参数名”)来获取数据

       const car= inject('car')
       return {
        car
      }

6.常用的响应式数据的判断

isRef:判断一个值是否是Ref对象

  console.log(isRef(obj))

isReactive:检查一个对象是不是由reactive创建的响应式代理

 console.log(isReactive(sum))

isReadonly: 检查一个对象是不是readonly创建的只读代理

console.log(isReadonly(readobj))

isProxy: 检查一个对象是不是由reactive或者readonly创建的代理

 console.log(isProxy(obj))

readonly修饰响应对象,还是proxy的

7.Composition组合PAI的优势

首先Vue2采用的OptionsAPI 它,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。比较杂乱

那么Vue3的compositionAPI可以让我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。(配合hook函数)

8.Fragment片段组件 内置组件直接用

Vue2组件必须要有根标签
而Vue3不需要有根标签,而是通过把组件标签打入一个虚拟的Fragment内部

9.Teleport(瞬间移动)内置组件直接用

Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。

  <Teleport to="body">
    <!-- to 写要传送的位置 可以直接写标签名 也可以通过标签选择器选择  #id
    如果是 用v-show控制的话,那么会预编译在to的位置 desplay none -->
  <div v-if="isshow">  
    <h1>对话内容</h1>
    <!-- 现在是弹在son组件里面  我想通过TelePort传送到 任意组件标签内 -->
    <h1>对话内容</h1>
    <h1>对话内容</h1>
    <button @click="isshow = false">点我关闭</button>
  </div>
</Teleport>

10.suspense(悬疑)组件和defineAsyncComponent异步引入组件

// 除了这种静态引入组件,还有异步引入组件得方式  
// 静态引入会等这个组件引入完 再显示
// import chilend from './components/chilend.vue'
import {defineAsyncComponent} from 'vue'
const child = defineAsyncComponent(()=>{
  // 异步引入 不需要等待  返回一个组件
  return import('./components/chilend.vue')
})


  <Suspense>  
    <!-- Suspense 是一个组件,他里面有两个插槽 一个default插槽是默认显示的
    一个fallback是default 有错误时显示的 比如加载满 -->
    <template v-slot:default>
      <child></child>
    </template>
    <template v-slot:fallback>
      <h1>加载中。。。。</h1>
    </template>
  </Suspense>

11.Vue3的一些变化

1.全局API的转移
Vue2使用Vue来定义
而Vue使用createApp返回的对象定义

组件的data一定要是函数,为了避免组价复用的时候数据错乱

2.移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes

3.移除v-on.native修饰符
在子组件中用emits声明的就是自定义事件 然就是原生事件

  export default {
    emits: ['close']
  }

4.移除过滤器(filter)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值