一、创建Vue3.0工程

1.使用 vue-cli 创建

官方文档:vue-cli

## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version
## 安装或者升级你的@vue/cli
npm install -g @vue/cli
## 创建
vue create vue_test
## 启动
cd vue_test
npm run serve

2.使用 vite 创建

官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite

vite官网:https://vitejs.cn

  • 什么是vite?—— 新一代前端构建工具。
  • 优势如下:
    • 开发环境中,无需打包操作,可快速的冷启动。
    • 轻量快速的热重载(HMR)。
    • 真正的按需编译,不再等待整个应用编译完成。
  • 传统构建 与 vite构建对比图
## 创建工程
npm init vite-app <project-name>
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev

二.常用 Composition API

1.理解:vue3.0中的一个新的配置项,值为一个函数

2.setup是所有组合API(composition)的基础

3.组件所用到的 数据 方法 ,都配置在setup中

4.setup的返回值为对象,对象的值为setup中的数据,方法注意点

  • 尽量不要与vue2.x的混用,vue2.x中可以访问到vue3.0的 数据与方法而3.x不能访问到 vue2.X的数据和方法

  • setup不能被 async 修饰,因为vue3.0.X的返回值注定是个对象,如果被 async 修饰,那返回值就成为一个 promise了,vue3.X并没对 为promise的情况进行处理,因此setup不能被async修饰

案例:

<template>
 <div>
   <h1>vue2.0</h1>
   <h3>{{msg01}}</h3>
   <button @click="sendMenth02">点我触发vue的方法</button>
   <hr>
   <h1>vue3.0</h1>
   <h3>这是vue3--{{name}}</h3>
   <button @click="sengmenth3">点我触发vue3的方法</button>
 </div>
</template>

<script> 
export default {
  name: 'App',
  data(){
    return {
      msg01:"这是vue2得用法"
    }
  },
  methods:{
    sendMenth02(){
        alert("这是vue2的方法")
        // vue2可以访问到vue3的数据和方法
        // this.sengmenth3()
        // console.log( this.name );
        // console.log( this.age );
      }
    },
    setup(){
      let name = '张三' 
      let age = 18
      function sengmenth3(){
        alert("这是vue3的方法")
        console.log( `我是${name},${age}岁` );
      }
      return {
        name,
        age,
        sengmenth3
      } 
  }
}
</script>

<style>
#app {
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

1.ref函数

概念:ref函数可以实现 响应式数据

语法:

import {ref} 'vue'
const name = ref('张三')
const obj = ref({
   kind:"web前端",
   salary:"30k"
}) 
  • 被ref函数包裹 返回一个 ref 引用实例对象

  • 修改被ref包裹的数据方式

     // 基本数据类型
     name.value = '李四'
     // 对象数据类型
     onj.value.kind = 'ui工程师'
     obj.value.salary = '60k'
    
  • 被ref包裹的基本数据类型返回一个ref引用实例,被包裹的对象通过其 reactive函数返回一个proxy对象,实现对象的响应式

2.reactive函数

  • 作用:定义一个对象类型的响应式数据(基本数据类型不用它,用ref)

  • 语法:reactive包裹一个对象或数组,返回一个被包裹后的代理对象

    const 代理对象 = reactive(源对象)
    
  • reactive 定义的数据是深层次的,可以被深度监听响应式

  • reactive 的底层是通过es6的proxy代理实现深度响应式

案例(骚写法):

<template>
  <div>
    <h1>vue3.0</h1>
    <h3>这是vue3----name-----{{person.name}}</h3>
    <h3>这是vue3-----age-----{{person.age}}</h3>
    <h3>这是vue3-----job-----{{person.obj.kind}}</h3>
    <h3>这是vue3-----salary-----{{person.obj.salary}}</h3>
    <button @click="sengmenth3">点我触发vue3的方法</button>
  </div>
</template>

<script>
import { ref,reactive } from "vue";
export default {
  name: "App",
  setup() {  
    let person = reactive({
      name:"张三",
      age:18,
      obj:{
        kind:"工程师",
        salary:'30k'
      }
    })
    function sengmenth3() {
       console.log( person ); 
       person.name="李四"
       person.age=20
       person.obj.kind='ui工程师'
       person.obj.salary='60k'
    }
    return {
      person,
      sengmenth3
    };
  }
};
</script>

<style>
#app {
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

3.vue2.0响应式原理

  • 实现原理

    • 对象类型:通过对 object.defindProperty() 对属性的读取 修改进行拦截(数据劫持)

      object.defindProperty()
      
    • 数组类型:通过重写数组的一系列方法来进行拦截(对数组的变更方法进行了拦截)

      push()
      pop()
      shift()
      unshift()
      splice()
      sort()
      reverse()
      

    vue2.0响应式存在的问题

    • 新增属性,删除属性也不会进行更新
    • 通过下标修改数组,页面不会进行更新

    原理模拟代码:

案例1:

   // vue2中的响应式 无法监听 对象 新增 和 删除 属性
          let person = {
              name: "张三",
              age: 18
          }
          let p = {}
          Object.defineProperty(p, "name", {
              configurable:true,
              get() {
                  console.log('读取了name属性', person.name);
                  return person.name
              },
              set(value) {
                  console.log('修改了name属性', value);
                  person.name = value
              }
          })

案例2:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <h1>你好,我是<span></span></h1>
        <h1>我来自于:<span></span></h1>
    </div>
    <script>
        let userinfo = {}
        Object.defineProperty(userinfo,'name',{
            configurable:true,
            get(){
                return document.getElementsByTagName('span')[0].innerHTML
            },
            set(val){
                return document.getElementsByTagName('span')[0].innerHTML = val
            }
        })
        Object.defineProperty(userinfo,'address',{
            get(){
                return document.getElementsByTagName('span')[1].innerHTML
            },
            set(val){
                return document.getElementsByTagName('span')[1].innerHTML = val
            }
        })
    </script>
</body>
</html>

4.vue3的响应式原理

  • 通过 Proxy代理,拦截对象中任意属性的变化,包括对象的新增属性,删除属性
  • 通过 Reflect 反射,对元对象属性进行操作
  // vue 3 响应式原理
        let per = {
            name:"li飞",
            age:15
        }
        // let p = new Proxy(per,{})
        // p 输出的结果 
        // [[Handler]]: Object 增删啊改 的 方法
        // [[Target]]: Object 源数据
        // [[IsRevoked]]: false 
       let p = new Proxy(per,{
            // 读取时 触发 
            get(target,propName){
                console.log( '当属性被读取时触发' );
                return Reflect.get(target,propName)
            },
            // 修改时 触发
            set(target,propName,newVal){
                console.log( "属性被修改时触发",target,propName,newVal );
                // target[propName] = newVal
                Reflect.set(target,propName,newVal) 
            },
            // 删除时 触发
            deleteProperty(target,propName){
                console.log( "属性被删除时触发" ,target,propName)
                // delete target[propName]
                Reflect.deleteProperty(target,propName)
            }
        })

5.reactive 和 ref 区别

  • 从定义数据的角度对比:
    • ref 用来定义:基本数据类型
    • reactive 用来定义:对象或数组类型
    • 备注:ref 也可以定义 数组或对象 ,它内部会通过 reactive函数转为代理对象
  • 从原理角度:
    • ref 底层通过 Object.defineProperty() 的get 和 set 来实现 响应式(数据劫持)
    • reactive 通过使用 Proxy 来实现响应式(数据劫持),并通过 Reflect 来操作源对象内部的数据
  • 从使用角度对比:
    • ref 定义的数据:操作数据需要 .value,读取数据时,模板中直接读取,不需要 .value
    • reactive 定义的数据:操作数据与读取数据:均不需要 .value

6. setup的注意点

  • setup 执行时机

    • 在 beforeCreate 之前,并且 其内部中的 this 为 undefined
  • setup两个参数

    • props: 值为对象,且为父组件传递过来的数据,且在组件中通过 props 接收的数据

    • context

      • attrs: 值为对象 且为父组件传递过来的数据,且没在 props中定义的数据
      • emit: 分发自定义事件的函数 相当于 this.$emit
      • s l o t : 收 到 的 插 槽 内 容 相 当 于 t h i s . slot: 收到的插槽内容 相当于 this. slot:this.slot
    • 案例

      父组件

      <template>
          <Demo01 @hello='currentEvent' msg="你好呀" school="清华" >
            <template v-slot:test1>
               <span>插槽</span>
            </template>
          </Demo01>
      </template>
      
      <script>
      import Demo01 from "./page/demo01.vue";
      export default {
        name: "App",
        components:{
          Demo01
        },
        setup(){
          function currentEvent(val){
            alert(`我接受到了子组件传递过来的数据${val}`)
          }
          return {
            currentEvent
          }
        }
      };
      </script>
      
      <style>
      #app {
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
      }
      </style>
      
      • 子组件
        <template>
          <div>
              <h1>{{msg}}</h1>
              <h1>{{school}}</h1>
              <button @click="sendData">点击发送数据到父组件</button>
          </div>
        </template>
        
        <script>
        export default {
            props:['msg'],
            emits:['hello'],
            beforeCreate(){
                console.log( "---- beforeCreate ----" );
            },
            setup(props,context){
                // setup 中的执行时机 正在 beforeCreate() 前 并且 this 为 undfind
                console.log( "---- setup ----",this );
                
                // 组件传递过来的参数 props 接收过的参数
                console.log( props );
                // 组件插槽
                console.log( context.slots );
                // 相当于 this.$attrs 且 没有在 props 中申明的参数
                console.log( context.attrs );
                // 子向父 传值
                function sendData(){
                    context.emit('hello',6666)  
                }
                return {
                    sendData
                }
            }
        }
        </script>
      

7.计算属性与监听器

1.computed

  • 与 vue2.x 的功能一致
  • 语法
<template>
  <div>
    <h1>vue3.0</h1>  
    <input type="text" v-model="p.startName" >
    <br>
    <input type="text" v-model="p.endName" >
    <br>
    <input type="text" v-model="p.fullName" >
  </div>
</template>

<script>
import { reactive,computed } from "vue";
export default {
  name: "App",
  setup() {  
    let p = reactive({
      startName:"张",
      endName:'三'
    })
    // get 当属性被读取时 触发
    // set 当属性被修改时 触发
    p.fullName = computed({
      get(){
        return p.startName + '-' + p.endName
      },
      set(val){
        let res = val.split('-')
        p.startName = res[0]
        p.endName = res[1]
      }
    })
    return {
      p
    };
  }
};
</script>

<style>
#app {
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

2.watch

  • 与Vue2.x中watch配置功能一致

  • 两个小“坑”

    • 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
    • 监视reactive定义的响应式数据中某个属性时:deep配置有效。
    //情况一:监视ref定义的响应式数据
    watch(sum,(newValue,oldValue)=>{
    	console.log('sum变化了',newValue,oldValue)
    },{immediate:true})
    
    //情况二:监视多个ref定义的响应式数据
    watch([sum,msg],(newValue,oldValue)=>{
    	console.log('sum或msg变化了',newValue,oldValue)
    }) 
    
    /* 情况三:监视reactive定义的响应式数据
    			若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!
    			若watch监视的是reactive定义的响应式数据,则强制开启了深度监视 
    */
    watch(person,(newValue,oldValue)=>{
    	console.log('person变化了',newValue,oldValue)
    },{immediate:true,deep:false}) //此处的deep配置不再奏效
    
    //情况四:监视reactive定义的响应式数据中的某个属性
    watch(()=>person.job,(newValue,oldValue)=>{
    	console.log('person的job变化了',newValue,oldValue)
    },{immediate:true,deep:true}) 
    
    //情况五:监视reactive定义的响应式数据中的某些属性
    watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
    	console.log('person的job变化了',newValue,oldValue)
    },{immediate:true,deep:true})
    
    //特殊情况
    watch(()=>person.job,(newValue,oldValue)=>{
        console.log('person的job变化了',newValue,oldValue)
    },{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
    

3.watchEffect函数

  • watch 监听器:既要指明监听的属性,也要指明监视的回调

  • watchEffect的回调是:不用指明监听哪个属性,监视的回调中用到那个属性,那就监听哪个属性

  • watchEffect有点像computed:

    • 但是computed更注重的是计算出来的值(回调函数的返回值),所以必须要写返回值
    • 而watch更注重的是过程(回调函数的函数体),所以不用写返回值
    //watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
    watchEffect(()=>{
        const x1 = sum.value
        const x2 = person.age
        console.log('watchEffect配置的回调执行了')
    })
    

8.vue3 生命周期

  **vue2 ------------------------- vue3**
  • beforeMount ===>onBeforeMount
  • mounted=======>onMounted
  • beforeUpdate===>onBeforeUpdate
  • updated =======>onUpdated
  • beforeUnmount ==>onBeforeUnmount
  • unmounted =====>onUnmounted
<template>
	<h2>当前求和为:{{sum}}</h2>
	<button @click="sum++">点我+1</button>
</template>

<script>
	import {ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'
	export default {
		name: 'Demo',
		
		setup(){
			console.log('---setup---')
			//数据
			let sum = ref(0)

			//通过组合式API的形式去使用生命周期钩子
			onBeforeMount(()=>{
				console.log('---onBeforeMount---')
			})
			onMounted(()=>{
				console.log('---onMounted---')
			})
			onBeforeUpdate(()=>{
				console.log('---onBeforeUpdate---')
			})
			onUpdated(()=>{
				console.log('---onUpdated---')
			})
			onBeforeUnmount(()=>{
				console.log('---onBeforeUnmount---')
			})
			onUnmounted(()=>{
				console.log('---onUnmounted---')
			})

			//返回一个对象(常用)
			return {sum}
		}
	}
</script>

9.自定义hook函数

  • 什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。

  • 类似于vue2.x中的mixin。

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

10.toRef 和 toRefs

1.toRef

  • 作用:创一个 ref对象,其 value 值 指向另一个对象中的某个属性

  • 语法;

    const person = { name:"张三" }
    const name = toRef(person,'name')
    
  • 应用:要将相应始终的某个属性 单独提供给外部使用时

  • 案例

    <template>
      <div>
        <h1>obj</h1>
          <hr>
        <h1>{{person}}</h1>
        <hr>
        <h3>{{name}}</h3>
        <h3>{{sex}}</h3>
        <h3>{{content.fit.age}}</h3>
        <h3>{{content.fit.money}}</h3>
        <button @click="name+=`--`">修改名字</button>
        <button @click="sex+=`-`">修改性别</button>
        <button @click="content.fit.age+=1">修改年龄</button>
        <button @click="content.fit.money+=1">修改年薪</button>
      </div>
    </template>
    
    <script>
    import { reactive,toRef,toRefs } from "vue";
    export default {
      name: "App",
      setup() { 
        let person = reactive({
          name:'张三',
          sex:"男",
          content:{
            fit:{
              age:18,
              money:20
            }
          }
        }) 
        return {
            name:toRef(person,'name'),
            sex:toRef(person,'sex'),
            age:toRef(person.content.fit,'age'),
            money:toRef(person.content.fit,'money')
        };
      }
    };
    </script>
    
    <style>
    #app {
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    

2.toRefs

  • 作用:创一个 ref对象,将多个 value 值 指向另一个对象中的多个属性

  • 语法:

    person = { name:"李晓飞",age:18 }
    const p = toRefs(person)
    
  • 应用:将多个响应式数据同时提供给外部使用

  • 案例

    <template>
      <div>
        <h1>obj</h1>
          <hr>
        <h1>{{person}}</h1>
        <hr>
        <h3>{{name}}</h3>
        <h3>{{sex}}</h3>
        <h3>{{content.fit.age}}</h3>
        <h3>{{content.fit.money}}</h3>
        <button @click="name+=`--`">修改名字</button>
        <button @click="sex+=`-`">修改性别</button>
        <button @click="content.fit.age+=1">修改年龄</button>
        <button @click="content.fit.money+=1">修改年薪</button>
      </div>
    </template>
    
    <script>
    import { reactive,toRefs } from "vue";
    export default {
      name: "App",
      setup() { 
        let person = reactive({
          name:'张三',
          sex:"男",
          content:{
            fit:{
              age:18,
              money:20
            }
          }
        }) 
        return {
          person,
          ...toRefs(person)
        };
      }
    };
    </script>
    
    <style>
    #app {
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
    

三.其它 Composition API

1.shallowReactive 与 shallowRef

  • shallowReactive :只处理对象的第一层数据为响应式数据(浅响应式)
  • shallowRef : 被包裹的对象 或 基本数据类型,将不再具有响应式的特征
  • 什么时候使用:
    • 如果一个对象嵌套结构比较深,并且只有最外层的数据变动,使用 ====> shallowReactive
    • 如果一个对象,后期将不对其内部的属性进行更改,那马使用 ====> shallowRef
  • 案例
<template>
  <div> 
    <h1>{{num.y}}</h1>
    <h1>{{num1.y}}</h1>
    <button @click="num.y++">num ++ 1</button>
    <button @click="num1.y++">num1 ++ 1</button>
    <hr>
    <h1>{{person}}</h1>
    <h3>姓名:{{ name }}</h3>
    <h3>年龄:{{ age }}</h3>
    <h3>薪资:{{ content.fit.salary }}</h3>
    <hr>
    <button @click="name+=`--`">修改名字</button> 
    <button @click="age++">修改年龄</button>
    <button @click="content.fit.salary++">修改年薪</button>
  </div>
</template>

<script>
import { shallowRef, shallowReactive,toRefs } from 'vue';
export default {
  name: "App",
  setup() { 
    // shallowReactive 浅响应式
    let person = shallowReactive({
      name:"张三",
      age:18,
      content:{
        fit:{
          salary:20
        }
      }
    })
    // 被 shallowRef 包裹的对象无法实现响应式
    let num = shallowRef({
      y:0
    })
    let num1 = shallowRef({
      y:0
    })
    return {
      num,
      num1,
      ...toRefs(person) 
    };
  }
};
</script>

<style>
#app {
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

2.readonly 和 shallowReadonly

  • readonly :让一个数据变为只读数据(深只读)

  • shallowReadonly : 让一个多层嵌套的数据变为 浅只读 数据(只有第一层数据只读)

  • 应用场景: 不希望数据被修改时。

  • 案例

    <template>
      <div> 
        <h1>{{num}}</h1>
        <button @click="num++">num +1</button>
        <hr>
        <h1>{{person}}</h1>
        <h3>姓名:{{ name }}</h3>
        <h3>年龄:{{ age }}</h3>
        <h3>薪资:{{ content.fit.salary }}</h3>
        <hr>
        <button @click="name+=`--`">修改名字</button> 
        <button @click="age++">修改年龄</button>
        <button @click="content.fit.salary++">修改年薪</button>
      </div>
    </template>
    
    <script>
    import { readonly,shallowReadonly,toRefs, reactive, ref } from 'vue';
    export default {
      name: "App",
      setup() { 
        // shallowReactive 浅响应式
        let num = ref(0)
        let person = reactive({
          name:"张三",
          age:18,
          content:{
            fit:{
              salary:20
            }
          }
        })
        // 把 person 变为 只读 数据
        num = readonly(num)
        // 把 person 变为 浅读 对象,只有第一层对象的数据只能读,不能修改
        person = shallowReadonly(person)
        return {
          num,
          ...toRefs(person) 
        };
      }
    };
    </script>
    
    <style>
    #app {
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    

3.toRaw 与 markRaw

  • toRaw
    • 作用:将一个由reactive生成的响应式对象转为普通对象
    • 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。
  • markRaw
    • 作用:标记一个对象,使其永远不会再成为响应式对象。
    • 应用场景:
      1. 有些值不应被设置为响应式的,例如复杂的第三方类库等。
      2. 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。

4.customRef

  • 作用:自定义ref , 对其 依赖项 进行 跟踪触发 更新视图

  • 案例:

    <template>
      <div>
        <input v-model="keyWord" type="text">
        <br>
        <h1>{{keyWord}}</h1>
      </div>
    </template>
    
    <script>
    import { customRef } from "vue";
    export default {
      name: "App",
      setup() { 
        function myref(value,delay){ 
          let timer = null
            return customRef((track,trigger)=>{
              return {
                get(){
                  console.log( "读取了value值",value );
                  track() // 追踪 最新的值
                  return value
                },
                set(newVal){
                 console.log( "修改后的最新值时",newVal );
                 clearTimeout(timer)
                 timer = setTimeout(()=>{
                      value = newVal
                      trigger()  // trigger vue通知模板解析
                  },delay) 
                }
              }
            }) 
        }
        // 自定义 ref
        let keyWord = myref('hello',500)
    
        return {
          keyWord
        };
      },
    };
    </script>
    
    <style>
    #app {
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    body {
      background-color: pink;
    }
    </style>
    
    

5.Provide Inject 通信

在这里插入图片描述

  • 通常,当我们需要从父组件向子组件传递数据时,我们使用 props。想象一下这样的结构:有一些深度嵌套的组件,而深层的子组件只需要父组件的部分内容。在这种情况下,如果仍然将 prop 沿着组件链逐级传递下去,可能会很麻烦。
  • provideinject。无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。这个特性有两个部分:父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这些数据。

案例文件结构

在这里插入图片描述

案例效果图

  • 祖父组件:

    <template>
      <div id="app"> 
        <h1>这里是根组件</h1>
         <button @click="sendData">点击---发送数据----修改价格</button>
        <Child1 />
      </div>
    </template>
    
    <script> 
    import Child1 from "./page/child/child1.vue";
    import { reactive,provide } from 'vue';
    export default {
      name: "App",
      components:{
        Child1
      },
      setup() {  
        let car =  reactive({
          name:"奔驰",
          price:20
        })
           provide('car',car) 
        function sendData(){
           car.price++
        } 
        return { 
          car,
          sendData
        };
      },
    };
    </script>
    
    <style>
    #app { 
      color: #2c3e50; 
      background-color: gold;
       padding: 10px;
    } 
    </style>
    
    
  • 子组件

    <template>
      <div class="zu">
          <h1>这里是子组件</h1>
          <Child2/>
      </div>
    </template>
    
    <script> 
    import Child2 from "./child2.vue";
    export default {
        components:{
            Child2
        }
    }
    </script>
    
    <style scoped >
    .zu{
        width: 500px; 
        background-color: pink;
        padding: 30px;
    }
    </style>
    
  • 祖孙组件

    <template>
      <div class="sun">
          <h1>这里是孙组件</h1>
          <h5 v-show="car">车名:{{car.name}}</h5>
          <h5 v-show="car">加个:{{car.price}}</h5>
      </div>
    </template>
    
    <script> 
    import { inject, watch } from "vue";
    export default { 
        setup(){
            let car = inject("car")  
            watch(car,(newVal)=>{
                console.log( newVal );
            },{deep:true,immediate:true})
            return {
               car 
            }
        }
    }
    </script>
    
    <style scoped >
    .sun{ 
        background-color: skyblue;
        padding: 30px;
    }
    </style>
    

6.响应式数据的判断

  • isRef: 检查一个值是否为一个 ref 对象
  • isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
  • isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
  • isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理

四、Composition API 的优势

1.Options API 存在的问题

使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改

2.Composition API 的优势

我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。

五.新的内置组件

1.Fragment

  • 在Vue2中: 组件必须有一个根标签
  • 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
  • 好处: 减少标签层级, 减小内存占用

2.Teleport

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

  • 效果图

    teleport内置组件

  • 案例结构:

    App.vue

    <template>
      <div id="app"> 
        <h1>这里是根组件</h1> 
        <Child1 />
      </div>
    </template>
    
    <script> 
    import Child1 from "./page/child-teleport/child1.vue"; 
    export default {
      name: "App",
      components:{
        Child1
      },
      setup() {  
        return {  
        };
      },
    };
    </script>
    
    <style>
    #app { 
      color: #2c3e50; 
      background-color: gold;
       padding: 10px;
    } 
    </style>
    

    child1

    <template>
      <div class="zu">
          <h1>这里是子组件</h1>
          <Child2/>
      </div>
    </template>
    
    <script> 
    import Child2 from "./child2.vue";
    export default {
        components:{
            Child2
        }
    }
    </script>
    
    <style scoped >
    .zu{
        width: 500px; 
        background-color: pink;
        padding: 30px;
    }
    </style>
    

    child2

    <template>
      <div class="sun">
        <h1>这里是孙组件</h1>
        <button @click="ishow = true">打开弹窗</button>
        <teleport to="body">
          <div v-if="ishow" class="mark">
            <div v-if="ishow" class="dialog">
              <button @click="ishow = false">关闭弹窗</button>
              <h1>这里是弹窗</h1>
              <h3>这里是内容</h3>
              <h3>这里是内容</h3>
              <h3>这里是内容</h3>
              <h3>这里是内容</h3>
              <h3>这里是内容</h3>
            </div>
          </div>
        </teleport>
      </div>
    </template>
    
    <script>
    import { ref } from "@vue/reactivity";
    export default {
      setup() {
        let ishow = ref(false);
        return { ishow };
      },
    };
    </script>
    
    <style scoped>
    .sun {
      background-color: skyblue;
      padding: 30px;
    }
    .dialog {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
      width: 300px;
      height: 300px;
      padding: 20px;
      background-color: green;
      color: honeydew;
      border-radius: 10px;
    }
    .mark {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      background-color: rgba(0, 0, 0, 0.6);
    }
    </style>
    

六、其他

1.全局API的转移

  • Vue 2.x 有许多全局 API 和配置。

    • 例如:注册全局组件、注册全局指令等。

      //注册全局组件
      Vue.component('MyButton', {
        data: () => ({
          count: 0
        }),
        template: '<button @click="count++">Clicked {{ count }} times.</button>'
      })
      
      //注册全局指令
      Vue.directive('focus', {
        inserted: el => el.focus()
      }
      
  • Vue3.0中对这些API做出了调整:

    • 将全局的API,即:Vue.xxx调整到应用实例(app)上

      2.x 全局 API(Vue3.x 实例 API (app)
      Vue.config.xxxxapp.config.xxxx
      Vue.config.productionTip移除
      Vue.componentapp.component
      Vue.directiveapp.directive
      Vue.mixinapp.mixin
      Vue.useapp.use
      Vue.prototypeapp.config.globalProperties

2.其他改变

  • data选项应始终被声明为一个函数。

  • 过度类名的更改:

    • Vue2.x写法

      .v-enter,
      .v-leave-to {
        opacity: 0;
      }
      .v-leave,
      .v-enter-to {
        opacity: 1;
      }
      
    • Vue3.x写法

      .v-enter-from,
      .v-leave-to {
        opacity: 0;
      }
      
      .v-leave-from,
      .v-enter-to {
        opacity: 1;
      }
      
  • 移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes

  • 移除v-on.native修饰符

    • 父组件中绑定事件

      <my-component
        v-on:close="handleComponentEvent"
        v-on:click="handleNativeClickEvent"
      />
      
    • 子组件中声明自定义事件

      <script>
        export default {
          emits: ['close']
        }
      </script>
      
  • 移除过滤器(filter)

    过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。

Logo

前往低代码交流专区

更多推荐