vue3中的其他变化

其他小改变

  • destroyed 生命周期选项被重命名为 unmounted
  • beforeDestroy 生命周期选项被重命名为 beforeUnmount
  • default prop 工厂函数不再可以访问 this 上下文
  • 自定义指令的 API 已更改为与组件生命周期一致,且 binding.expression 已移除
  • data 选项应始终被声明为一个函数
  • 来自 mixin 的 data 选项现在为浅合并
  • Attribute 强制策略已更改
  • 一些过渡的 class 被重命名
  • <TransitionGroup> 不再默认渲染包裹元素
  • 当侦听一个数组时,只有当数组被替换时,回调才会触发,如果需要在变更时触发,则必须指定 deep 选项
  • 没有特殊指令的标记 (v-if/else-if/elsev-for 或 v-slot) 的 <template> 现在被视为普通元素,并将渲染为原生的 <template> 元素,而不是渲染其内部内容。
  • 已挂载的应用不会取代它所挂载的元素
  • 生命周期的 hook: 事件前缀改为 vnode-

被移除的 API

  • keyCode 作为 v-on 修饰符的支持
  • $on、$off 和 $once 实例方法
  • 过滤器 (filter)
  • 内联模板 attribute
  • $children 实例 property
  • propsData 选项
  • $destroy 实例方法。用户不应再手动管理单个 Vue 组件的生命周期。
  • 全局函数 set 和 delete 以及实例方法 $set 和 $delete。基于代理的变化检测已经不再需要它们了。

在prop的默认函数中访问this

vue3中,生成prop默认值的工厂函数不再能访问this

替代方案:

  • 把组件接收到的原始 prop 作为参数传递给默认函数;
  • inject API 可以在默认函数中使用

案例:

app.vue

<template>
   <div>
   <defaults :parentMsg="parentMsg"></defaults>
   </div>
</template>

<script>
import defaults from "./components/default.vue"
   export default {
      components:{
         defaults
      },
      data(){
         return {
            parentMsg:'父组件数据'
         }
      }
   }
</script>

 default.vue

<template>
    <div>
        props默认值的工厂函数
        <br/>
        {{parentMsg}}
    </div>
</template>

<script>
    export default {
        props:{
            parentMsg:{
                default:'默认值'
            }
        }
    }
</script>

 此时正常加载数据

 

 

 此时我们不接受父组件传来的数据时,默认显示的是默认值

<template>
   <div>
   <defaults ></defaults>
   </div>
</template>

 

 

 可以使用工厂函数返回一个值

<template>
    <div>
        props默认值的工厂函数
        <br/>
        {{parentMsg}}
    </div>
</template>

<script>
    export default {
        props:{
            parentMsg:{
                default(){
                    return "工厂函数的值"
                }
            }
        }
    }
</script>

 

 

prop默认值的工厂函数不再能访问this

我们可以看一下输出的this是什么

  props:{
            parentMsg:{
                default(){
                    console.log(this,'this');
                    return "工厂函数的值"
                }
            }
        }

 

 

 把组件接收到的原始 prop 作为参数传递给默认函数,这个prop是传递给组件的原始值

 

 

 我们输出prop看一下

console.log(prop,'prop');

 

 

 inject API 可以在默认函数中使用

在任何类型/默认强制转换之前,也可以使用inject来访问注入的property

app.vue

<template>
   <div>
   <defaults ></defaults>
   </div>
</template>
<script>
import defaults from "./components/default.vue"
import {provide} from "vue"
   export default {
      components:{
         defaults
      },
      data(){
         return {
            parentMsg:'父组件数据'
         }
      },
      setup(){
         // 第一个注入属性的名字,第二个是对应的值
         provide('theme',"provideTheme")
      }
   }
</script>

 default.vue

<template>
    <div>
        props默认值的工厂函数
        <br/>
        {{parentMsg}}
    </div>
</template>

<script>
import {inject} from 'vue'
    export default {
        props:{
            parentMsg:{
                default(prop){
                    console.log(prop,'prop');
                    return inject('theme','defaultTheme')
                }
            }
        }
    }
</script>

自定义指令 API 已更改为与组件生命周期一致

vue3中指令api和组件的api保持一致,具体的表现有:

  • created - 新增!在元素的 attribute 或事件监听器被应用之前调用。
  • bind → beforeMount
  • inserted → mounted
  • beforeUpdate:新增!在元素本身被更新之前调用,与组件的生命周期钩子十分相似。
  • update → 移除!该钩子与 updated 有太多相似之处,因此它是多余的。请改用 updated
  • componentUpdated → updated
  • beforeUnmount:新增!与组件的生命周期钩子类似,它将在元素被卸载之前调用。
  • unbind -> unmounted

案例:

main.js

我们新建一个自定义指令

import { createApp,createRenderer} from "vue";

import App from "./App.vue";

createApp(App)
.directive('light',{
    beforeMount(el,binding,vnode){
        el.style.color=binding.value
    }
})
.mount("#app");

 app.vue

<h1 v-light="'red'">自定义指令内容变色</h1>

 

Data选项始终被声明为一个函数

  • 非兼容:组件选项 data 的声明不再接收纯 JavaScript object,而是接收一个 function
  • 非兼容:当合并来自 mixin 或 extend 的多个 data 返回值时,合并操作现在是浅层次的而非深层次的 (只合并根级属性)

vue3中data选项统一为函数形式,返回响应式数据

在 2.x 中,可以通过 object 或者是 function 定义 data 选项。

<!-- Object 声明 -->
<script>
  const app = new Vue({
    data: {
      apiKey: 'a1b2c3'
    }
  })
</script>

<!-- Function 声明 -->
<script>
  const app = new Vue({
    data() {
      return {
        apiKey: 'a1b2c3'
      }
    }
  })
</script>

在 3.x 中,data 选项已标准化为只接受返回 object 的 function

<script>
  import { createApp } from 'vue'

  createApp({
    data() {
      return {
        apiKey: 'a1b2c3'
      }
    }
  }).mount('#app')
</script>

 Mixin 合并行为变更

将共享数据提取到外部对象并将其用作 data 中的 property

重写对共享数据的引用以指向新的共享对象

当来自组件的 data() 及其 mixin 或 extends 基类被合并时,合并操作现在将被浅层次地执行:

const Mixin = {
  data() {
    return {
      user: {
        name: 'Jack',
        id: 1
      }
    }
  }
}

const CompA = {
  mixins: [Mixin],
  data() {
    return {
      user: {
        id: 2
      }
    }
  }
}

在 Vue 2.x 中,生成的 $data 是:

{
  "user": {
    "id": 2,
    "name": "Jack"
  }
}

在 3.0 中,其结果将会是:

{
  "user": {
    "id": 2
  }
}

Transition类名变更

vue2中

 

  vue3中,过渡类名  v-enter 修改为  v-enter-from、过渡类名  v-leave 修改为  v-leave-from

 

transition.vue

<template>
    <div id="demo">
        <button @click="show=!show">change</button>
        <Transition name="fade">
           <div class="box" v-if="show"></div>
        </Transition>
    </div>
</template>
<script>
export default {
    data(){
        return {
            show:true
        }
    }
}
</script>
<style>
.box{
    width: 200px;
    height: 200px;
    background-color: red;
}

.fade-enter-active,
.fade-leave-active{
    transition:all 1s ;
}

.fade-enter-from,
.fade-leave-to{
    opacity: 0;
}
</style>

 app.vue

<template>
   <div>
   <transitions></transitions>
   </div>
</template>
<script>
import transition from "./components/transition.vue"

import {provide} from "vue"
   export default {
      components:{
         transitions
      }
 
</script>

watch变更

vue3中,当侦听一个数组时,只有当数组被替换时才会触发回调。如果你需要在数组改变时触发回调,必须指定 deep 选项

watch: {
  bookList: {
    handler(val, oldVal) {
      console.log('book list changed')
    },
    deep: true
  },
}

 watch.vue

<template>
    <div>
        <button @click="change">替换</button>
       <ul>
           <li v-for="(item,index) in list" :key="item.id">
               {{item.name}}  <button @click="del(index)"> 删除</button>
           </li>
       </ul>
    </div>
</template>
<script>
export default {
    data(){
        return {
            list:[
                {id:1,name:"js"},
                {id:2,name:"html"},
                {id:3,name:"vue"},
                {id:4,name:"css"}
            ]
        }
    },
    watch:{
        booklist:{
            handler(val,oldval){
                console.log("booklist changed")
            },
            // 数组改变时触发回调,必须指定deep选项
            deep:true
            
        }
    },
    methods:{
        del(index){
            this.list.splice(index,1)
        },
        change(){  //数组替换
          this.list=[
                {id:1,name:"语文"},
                {id:2,name:"数学"},
                {id:3,name:"英语"},
                {id:4,name:"体育"}
          ]

        }
    }
}
</script>

 

没有特殊指令的标记 (v-if/else-if/elsev-for 或 v-slot) 的 <template> 现在被视为普通元素,并将渲染为原生的 <template> 元素,而不是渲染其内部内容。

被挂载的应用不会替换元素

 在 Vue 2.x 中,当挂载一个具有 template 的应用时,被渲染的内容会替换我们要挂载的目标元素。在 Vue 3.x 中,被渲染的应用会作为子元素插入,从而替换目标元素的 innerHTML

 在 Vue 2.x 中,我们为 new Vue() 或 $mount 传入一个 HTML 元素选择器

<body>
    <div id="app">
        
      </div>
  <script>
      new Vue({
          el: '#app',
          data() {
            return {
              message: 'Hello Vue!'
            }
          },
          template: `<div id="rendered">{{ message }}</div>`  
        })


  </script>
</body>

在渲染结果中,上面提及的 div 将会被应用所渲染的内容替换:

 

 在 Vue 3.x 中,当我们挂载一个应用时,其渲染内容会替换我们传递给 mount 的元素的 innerHTML

<body>
    <div id="app">
        
      </div>
  <script>
     const app = Vue.createApp({
  data() {
    return {
      message: 'Hello Vue!'
    }
  },
  template: `
    <div id="rendered">{{ message }}</div>
  `
})
app.mount('#app')
  </script>
</body>

当这个应用挂载到拥有匹配 id="app" 的 div 的页面时,结果会是:

 

 生命周期的 hook: 事件前缀改为 vnode-

 

在 Vue 2 中,我们可以通过事件来监听组件生命周期中的关键阶段。这些事件名都是以 hook: 前缀开头,并跟随相应的生命周期钩子的名字。

这些事件名和相应的生命周期钩子一致,并带有 hook: 前缀:

<template>
  <child-component @hook:updated="onUpdated">
</template>

在 Vue 3 中,这个前缀已被更改为 vnode-。额外地,这些事件现在也可用于 HTML 元素,和在组件上的用法一样。

事件名附带的是 vnode- 前缀:

<template>
  <child-component @vnode-updated="onUpdated">
</template>

或者在驼峰命名法的情况下附带前缀 vnode

<template>
  <child-component @vnodeUpdated="onUpdated">
</template>

  

posted @ 2021-11-11 18:26  keyeking  阅读(815)  评论(0编辑  收藏  举报