vue3.0的变化与2.0的区别【一】

生命周期的变化

vue3.x的生命周期

 

 vue2.x

 

 

 对比之下可以看出来vue3.0和vue2.0之间生命周期函数在销毁的时候有区别

beforeUnmount -->beforeDestroy
unmounted-->destroyed

定义全局变量的方法变化

vue2.x

Vue.prototype.$axios = () => {}

vue3.x

const app = createApp({})
app.config.globalProperties.$axios = () => {}

创建vue实例化

vue2.x

import Vue from 'vue'
import App from './App.vue'
import router from './router'
 Vue({
  router,
  render: h => h(App)
}).$mount('#app')

vue3.x


 //使用createApp函数来实例化vue
//该函数接收一个根组件选项对象作为第一个参数
//
使用第二个参数,我们可以将根 prop 传递给应用程序
import { createApp } from 'vue' import App from './App.vue' import router from './router'
var app = createApp(App)
app.use(router)

app.mount('#app') //由于 createApp 方法返回应用实例本身,因此可以在其后链式调用其它方法。

插槽使用变化

vue2.x

vue 在 2.6.0 中,具名插槽和作用域插槽引入了一个新的统一的语法 :v-slot 指令。
它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍有用的特性。
但是将会在vue 3 中,这两个指令将会被废弃

子组件

<template>
  <div class="my-card">
        <!-- 把数据传给父组件,接收作用域插槽 !-->
    <!--

父组件复用子组件的时候 对某一个子组件内容样式不满意 此时在 子组件内你希望改变的那部分内容外 包裹一个slot标签 给slot自定义一个属性(名称自己起)父组件模板定义一个slot-scope="slot"属性 模板内通过slot.xxx可以拿到子组件的数据 拿到数据后就好办了 可以任你蹂躏了 你想把它弄成什么样就弄成什么样!-->

    <!--父组件改变了子组件的样式 但是内容还是子组件的!-->
<slot name="scope_slot" :user=user :text=text></slot> <!-- 接收具名插槽 !-->
<!--在子组件template属性中添加多个slot标签 而这个slot标签都各自带有自己的name属性 属性值都不一样!-->
    <!--父组件可以对应不同的name值 把相对应的内容 插入到各自slot标签里!-->
    <!--slot标签内可以包裹任意原子组件的内容 插入的内容将会替换掉它!-->
<slot name="named_slot"></slot>
    
      <!-- 接收默认匿名插槽 !-->
    <!--在子组件template属性中添加一个slot标签 而这个slot标签不带name属性!-->
    <!--父组件里任何内容都默认加到这个slot标签里!-->
<!--slot标签内可以包裹任意原子组件的内容 插入的内容将会替换掉它!-->
    <slot></slot> 
  </div>
</template>
<script>
export
default {
name:
'card',
data()
{
return{
user:[
{ name:
'张三', age:'21' },
{ name:
'李四', age:'20' } ],
text:{ msg:
'作用域插槽' }
  }
}
}

</script>

父组件

<template>
  <div class="home-container">
      <h1>Home</h1>
      <card>
          <!-- 作用域插槽  v-slot:插槽名 = '接受子组件数据的对象名,可自定义' -->
          <template v-slot:scope_slot = 'item'>
              <h1>{{item.text.msg}}</h1>
              <div v-for="u in item.user" :key='u'>
                  <h3>{{u.name}}</h3>
              </div>
          </template>
          
          <!-- 具名插槽 v-slot:插槽名字 -->
          <template v-slot:named_slot>
              <h1>具名插槽</h1>
          </template>


          <template>
              <h1>匿名插槽</h1>
          </template>
      </card>
  </div>
</template>

vue3.x

//在vue3.0中,插槽使用v-slot 简写用#
<div>    
   <slot name="test" :newData="slotsData"></slot>
   <slot></slot>
</div>
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App">
    <template #default> // 可以写为v-slot:default
       <div>默认插槽</div>
    </template>
    //作用域插槽
    <template #test="{ newData }"> // 可以写为v-slot:test="newData"
      <p>{{ newData.aa }}</p>
      <p>{{ newData.bb }}</p>
    </template>
</HelloWorld>
//一个组件里面具有多个插槽时,一定要带上名称,否则可能会导致作用域错乱

自定义指令

vue2.x

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})

在 Vue 2 中, 自定义指令通过以下几个可选钩子创建:

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。

update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

unbind:只调用一次,指令与元素解绑时调用。

 

vue3.x

const { createApp } from "vue"

const app = createApp({})
app.directive('focus', {
    mounted(el) {
        el.focus()
    }
})

双向数据绑定

 vue2.x

VUe2.0通过Object.definePropety来劫持对象属性的getter和setter操作,当数据发生变化时通知

 

 

vue3.x

vue3.0通过Proxy来劫持数据,当数据发生变化时发出通知

 

 

proxy相较于object.defineProperty的优势

  1. defineProperty只能监听某个属性,不能对全对象监听
  2. Proxy可以监听数组的变化,不用再去单独的对数组做特异性操作
  3. 可以检测到数组内部数据的变化

异步组件的使用

vue2定义异步组件

<template> <div> <button @click="show = true">Load Tooltip</button> <div v-if="show"> <Tooltip /> </div> </div> </template> <script> export default { data: () => ({ show: false }), components: { Tooltip: () => import('./components/Tooltip') } } </script>

 

vue3中使用defineAsyncComponent 定义异步组件

<template>
  <!-- 异步组件的使用 -->
  <AsyncPage />
</tempate>

<script>
import { defineAsyncComponent } from "vue";

export default {
  components: {
    // 无配置项异步组件
    AsyncPage: defineAsyncComponent(() => import("./NextPage.vue")),

    // 有配置项异步组件
    AsyncPageWithOptions: defineAsyncComponent({
   loader: () => import(".NextPage.vue"),
   delay: 200,
   timeout: 3000,
   errorComponent: () => import("./ErrorComponent.vue"),
   loadingComponent: () => import("./LoadingComponent.vue"),
 })
  },
}
</script> 

Composition API

使用Composition API 解决我们在完成功能时,在 data、methods、computed 以及 mounted 中反复的跳转,他将零散分布的 逻辑组合在一起维护,并可以将单独的逻辑再分为单独的文件

  • setup

  1. setup是Vue3.x的新增选项,是组件内使用Composition API的入口
    <script>
    import { defineComponent, reactive } from "vue";
    export default defineComponent({
        beforeCreate() {
            console.log("++++beforeCreate+++++");
        },
        created() {
            console.log("+++created+++");
        },
        setup() {
            const state = reactive({ count: 0 });
            console.log("++++setup++++++");
            return {
                state,
            };
        },
    });
    </script>

     输出结果: 

                 

      总结:setup 执行时机是在 beforeCreate 之前执行

setup参数

setup接收两个参数(propscontext),props是响应式的,当传入新的props时,会及时更新。由于是响应式的,所以不可以使用ES6解构,解构会消除它的响应式

setup(props) {
    const { userName } = props;
    console.log(userName );
    const state = reactive({ num: 0 });
    return {
      state,
    };
  },

reactive、ref、toRefs

 在 vue2.x 中, 定义数据都是在data中。Vue3.x可以使用reactive和ref来进行数据定义

reactive用于处理对象的双向绑定 

ref处理js基础数据类型或者处理对象的双向绑定

 

<template>
  <div>
    <p>计数:{{ num }}s</p>
    <p>人年龄:{{ person.age }}</p>
    <p>人姓名:{{ person.name }}</p>
    <p>狗类别:{{ dog.type }}</p>
    <p>狗名称:{{ dog.name }}</p>
    <p>狗年龄:{{ dog.age }}</p>
  </div>
</template>
<script>
import { defineComponent, reactive, ref } from "vue";
export default defineComponent({
  setup() {
    //使用ref声明基本类型
    const num = ref(0);
    //使用ref声明对象
    const person = ref({ age: 20, name: "张三" });
    //使用reactive声明对象
    const dog= reactive({ type: "金毛", name: "小花", age: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "李四";
      dog.age++;
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);
    return {
      num,
      dog,
      person,
    };
  },
});
</script>

 

通过绑定dog.name,dog.type写的比较繁琐,就需要解构数据,但是又不能又ES6解构,因为会会消除props响应式。既想要解构后的数据又不使用解构,解决办法就是使用toRefs。

toRefs作用就是将一个reactive对象转化为属性全部为ref对象的普遍对象

<template>
  <div>
    <p>计数:{{ num }}s</p>
    <p>人年龄:{{ person.age }}</p>
    <p>人姓名:{{ person.name }}</p>
    <p>狗类别:{{ type }}</p>
    <p>狗名称:{{ name }}</p>
    <p>狗年龄:{{ age }}</p>
  </div>
</template>
<script>
import { defineComponent, reactive, ref ,toRefs} from "vue";
export default defineComponent({
  setup() {
    //使用ref声明基本类型
    const num = ref(0);
    //使用ref声明对象
    const person = ref({ age: 20, name: "张三" });
    //使用reactive声明对象
    const dog= reactive({ type: "金毛", name: "小花", age: 5 });
    setTimeout(() => {
      person.value.age = person.value.age + 1;
      person.value.name = "李四";
      dog.age++;
    }, 1000);
    setInterval(() => {
      num.value++;
    }, 1000);
    return {
      num,
      ...toRefs(dog),
      person,
    };
  },
});
</script>
  • 生命周期钩子

vue3.x

 

import {
  defineComponent,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured,
  onRenderTracked,
  onRenderTriggered,
} from "vue";
export default defineComponent({
  setup() {
    console.log("setup");
    onBeforeMount(() => {
      console.log("onBeforeMount");
    });
    onMounted(() => {
      console.log("onMounted");
    });
    onBeforeUpdate(() => {
      console.log("onBeforeUpdate");
    });
    onUpdated(() => {
      console.log("onUpdated");
    });
    onBeforeUnmount(() => {
      console.log("onBeforeUnmount");
    });
    onUnmounted(() => {
      console.log("onUnmounted");
    })
  },
});

 

vue2.x

<script>

 export default{
      el: '#app',
      data: {
          message : "boy" 
      },
       beforeCreate() {
                console.group('beforeCreate 创建前状态===============》');
           
        },
        created() {
            console.group('created 创建完毕状态===============》');
        
        },
        beforeMount() {
            console.group('beforeMount 挂载前状态===============》');
    
        },
        mounted() {
            console.group('mounted 挂载结束状态===============》');
        
        },
        beforeUpdate() {
            console.group('beforeUpdate 更新前状态===============》');
        
        },
        updated() {
            console.group('updated 更新完成状态===============》');
          
        },
        beforeDestroy() {
            console.group('beforeDestroy 销毁前状态===============》');
         
        },
        destroyed() {
            console.group('destroyed 销毁完成状态===============》');
      
        }
    }
</script>

 

posted @ 2021-10-14 14:38  卡布奇诺。不加糖  阅读(880)  评论(0)    收藏  举报