vue2与vue3对比

阅读数:157 评论数:0

跳转到新版页面

分类

html/css/js

正文

一、生命周期

1、vue2生命周期

beforeCreate #实例初始化之后,进行数据侦听和事件/侦听器的配置之前同步调用
created #实例创建完成后被立即同步调用
beforeMount #挂载开始之前被调用
mounted #实例被挂载后调用
beforeDestroy #
destroyed #
beforeUpdate  #数据发生改变后,DOM 被更新之前被调用
updated #虚拟 DOM 重新渲染和更新完毕之后被调用
activated #keep-alive 缓存的组件激活时调用
deactivated # keep-alive 缓存的组件失活时调用

2、vue3生命周期

vue3中新引入了setup生命周期,setup在beforeCreate生命周期之前执行,这个时候data与methods还没有初始化,dom没有挂载,意味着在setup方法里不能获取data、methods、computed与dom。

destroyed生命周期选项被重命名为unmounted

beforeDestroy生命周期选项被重命名为beforeUnmount

(1)vue2到vue3映射关系

beforeCreate -> use setup() 创建实例前
created -> use setup()
beforeMount -> onBeforeMount 挂载dom前
mounted -> onMounted 挂载dom后
beforeUpdate -> onBeforeUpdate 更新组件前
updated -> onUpdated  更新件后
beforeDestroy -> onBeforeUnmount 卸载销毁前
destroyed -> onUnmounted 卸载销毁后
errorCaptured -> onErrorCaptured

(2)引用时只需导入钩子并将它闪包在setup方法中即可。

import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onActivated, onDeactivated, onErrorCaptured } from 'vue'
export default {
  setup() {
    onBeforeMount(() => {
      // ... 
    })
    onMounted(() => {
      // ... 
    })
    onBeforeUpdate(() => {
      // ... 
    })
    onUpdated(() => {
      // ... 
    })
    onBeforeUnmount(() => {
      // ... 
    })
    onUnmounted(() => {
      // ... 
    })
    onActivated(() => {
      // ... 
    })
    onDeactivated(() => {
      // ... 
    })
    onErrorCaptured(() => {
      // ... 
    })
  }
}

二、绑定数据

1、vue2中使用Object.defineProperty劫持数据,即其中的get和set方法,使用发布订阅模式实现数据绑定。

var obj= { name:"banana" };
var name = "apple"
Object.defineProperty(obj, "name", {
  get : function() { return name; },
  set : function(newValue) { name = newValue; },
  value: "banana",
  writable: true,  // 为 true 时, value才能被赋值运算符改变 默认是false
  enumerable : true,   // 能否枚举 默认是false
  configurable : true // 描述符能够被改变 默认是false
});

Object.defineProperty的缺陷在于需要尝试遍历并对每个属性进行劫持,而对于没有属性数组而言,数组的索引也可以视为被支持的属性,但是和对象相同,对于新增的元素而言,不会触发监听事伯,vue对此的解决方案是支持数组原型链上的函数,即便如此也仍旧无法监听数组长度的修改。

2、vue3中使用Proxy代理

vue2使用es5的Object.defineProperty,vue3使用es6的Proxy。Proxy可以直接监听对象而非属性,也可以直接监听数组的变化,重点还是很好的性能。

Proxy可以监听对象的基本操作,而defineProperty是对象基本操作的一个。

通过下例来理解:

  <script>
        var target = {
            name: "xiaoming",
            age: 18
        }

        // handler 是一个对象
        const handler = {
            set(target, prop, value) {
                let result = Reflect.set(target, prop, value)
                console.log("设置的操作" + result)
                return true;
            },
            get(target, value) {
                let result = Reflect.get(target, value)
                console.log("获取的的操作" + result)
            }
        }

        let proxy = new Proxy(target, handler);
        proxy.coure = "java"
        console.log(proxy)
    </script>

handler可以有以下几种属性

get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy['foo']。
set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。

三、定义数据和方法

1、vue2定义数据使用data,定义方法使用methods

export default {
    name: 'App',
    data(){
        return {
            title: 'vue3',
            num: 3
        }
    },
    methods:{
        hello () {
            alert('hello vue3');
        }
    }
}

2、vue3

(1)定义数据和方法在setup()方法里面,return一个对象

由于执行setup函数时,组件实例还未创建,因此this是undefined。

export default {
    name: 'App',
    setup(){
        return {
            title: 'vue3',
            num: 3,
            hello () {
                alert('hello vue3');
            }
        }
    }
}

(2)reactive函数(定义响应式数据)

<template>
    <div class="container">
        <div>{{ obj.name }}</div>
        <div>{{ obj.age }}</div>
        <button @click="changeName">修改名字</button>
    </div>
</template>

<script>
import { reactive } from 'vue'
export default {
    name: 'App',
    setup() {
        // 普通数据
        // const obj = {
        //     name: 'HS',
        //     age: 18,
        // }

        // 响应式数据
        const obj = reactive({
            name: 'HS',
            age: 18,
        })

        // 修改名字
        const changeName = () => {
            obj.name = "ZJP";
        }
        return { obj, changeName }
    }
}
</script>

(3)toRef函数(定义响应式数据)

<template>
    <div>
        {{ name }}
        <button @click="updateName">修改名字</button>
    </div>
</template>

<script>
import { reactive, toRef } from 'vue'
export default {
    name: 'App',
    setup() {
        // 1.响应式数据对象
        const obj = reactive({
            name: 'HS',
            age: 18,
        })

        // 2.模板中只需要使用name数据
        // 注意:从响应式数据对象中结构出来的属性数据,不再是响应式数据
        // const { name } = obj; 不能直接解构,出来的是一个普通数据
        const name = toRef(obj, 'name');
        const updateName = () => {
            // toRef转换响应式数据包装成对象,value是存放值的位置
            name.value = "ZJP";
        }
        return {
            name,
            updateName,
        }
    }
}
</script>

(4)toRefs(定义响应式数据)

<template>
    <div>
        {{ name }}
        {{ age }}
        <button @click="updateName">修改名字</button>
    </div>
</template>

<script>
import { reactive, toRefs } from 'vue'
export default {
    name: 'App',
    setup() {
        // 1.响应式数据对象
        const obj = reactive({
            name: 'HS',
            age: 18,
        })
        // 2.解构或者展开响应式数据对象
        // const { name, age } = obj;
        // console.log(name, age);
        // const obj2 = { ...obj };
        // console.log(obj2);
        // 以上方式导致数据就不是响应式数据了
        const obj3 = toRefs(obj);
        console.log(obj3);

        const updateName = () => {
            obj3.name.value = "ZJP";
        }
        return {
            ...obj3,
            updateName,
        }
    }
}
</script>

(5)ref函数(定义响应式数据)

常用于简单类型定义为响应式数据。

<template>
    <div>
        {{ name }}
        <button @click="updateName">修改名字</button>
    </div>
</template>

<script>
import { ref } from 'vue';
export default {
    name: 'App',
    setup() {
        const name = ref("HS");
        const updateName = () => {
            name.value = "ZJP";
        }

        return {
            name,
            updateName,
        }
    }
}
</script>

(6)computed函数

<template>
  <div class="container">
    <div>今年:{{age}}岁</div>
    <div>后年:{{newAge}}岁</div>
  </div>
</template>
<script>
import { computed, ref } from 'vue'
export default {
  name: 'App',
  setup () {
    // 1. 计算属性:当你需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据。
    const age = ref(16)
    // 得到后年的年龄
    const newAge = computed(()=>{
      // 该函数的返回值就是计算属性的值
      return age.value + 2
    })

    return {age, newAge}
  }
}
</script>

另一种写法

<template>
    <div class="container">
        <div>今年:{{ age }}岁</div>
        <div>后年:{{ newAge }}岁</div>
        <input type="number" v-model="newAge" />
    </div>
</template>
<script>
import { computed, ref } from 'vue'
export default {
    name: 'App',
    setup() {
        // 1. 计算属性:当你需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据。
        const age = ref(16)
        // 得到后年的年龄
        const newAge = computed({
            // get函数,获取计算属性的值
            get() {
                return age.value + 2
            },
            // set函数,当你给计算属性设置值的时候触发
            set(value) {
                age.value = value - 2;
            }
        })

        return { age, newAge }
    }
}
</script>

(7)watch函数

<!-- name -->
<template>
  <div>
    <input type="text" v-model="name1" />
    <input type="text" v-model="name2" />
    <input type="text" v-model="name3.aaa.bbb.ccc" />
    {{ name3 }}
  </div>
</template>

<script lang="ts" setup>
import { computed, reactive, ref, watch } from "vue";

/**
 *
 */

interface bbb {
  ccc: String;
}

interface aaa {
  bbb: bbb;
}

interface text {
  aaa: aaa;
}

const name1 = ref<string>("");
const name2 = ref<string>("");
const name3 = ref<text>({
  aaa: {
    bbb: {
      ccc: "123",
    },
  },
});

// 情况一:监听单个
// watch(name1, (newValue, oldValue) => {
//   console.log(newValue, oldValue);
// });

// 情况二:监听多个  --- 以数组的形式书写,同时newValue, oldValue返回值也是数组
// watch([name1, name2], (newValue, oldValue) => {
//   console.log(newValue, oldValue);
// });

// 情况三:监听对象  --- 如果为ref则需要开启第三个属性 deep: true,
//                  --- 如果为reactive则不需要开启第三个属性
//                  --- 注意:监听到的对象都是新的返回值
// watch(
//   name3,
//   (newValue, oldValue) => {
//     console.log(newValue, oldValue);
//   },
//   {
//     deep: true,
//     immediate: true, // 立即执行一次
//     flush: "post", // pre 默认值 组件更新前调用  sync 同步调用  post 组件更新后调用
//   }
// );

//  情况四:监听对象的某个属性,需要声明reactive,同时写成一个类似get的形式把要监听的属性返回
watch(
  () => name3.aaa.bbb.ccc,
  (newValue, oldValue) => {
    console.log(newValue, oldValue);
  }
);
</script>

<style scoped lang="scss"></style>

四、指令

1、v-model

(1)vue2

<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />

(2)vue3

<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent
  :modelValue="pageTitle"
  @update:modelValue="pageTitle = $event"
/>
###### 变化
prop:value => modelValue
事件:input => update:modelValue

2、v-if和v-for优先级

在vue2中,v-for的优先级高。

在vue3中,v-if的优先级高。

五、修饰符

1、v-on.native

在vue2中,v-on.native修饰符把原生的事件绑定到子组件根元素上。

<my-component
  v-on:close="handleComponentEvent"
  v-on:click.native="handleNativeClickEvent"
/>

在vue3中,.native修饰符已被移除,同时新增emits选项

<my-component
  v-on:close="handleComponentEvent"
  v-on:click="handleNativeClickEvent"
/>

子组件

<script>
  export default {
    emits: ['close']
  }
</script>

六、mixin

vue3中更推荐使用hook(组合api)

1、全局混入

// main.js
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
// vue2.0 Vue.mixin({ 全局混入的选项对象 })
// vue3.0 app.mixin({ 全局混入的选项对象 })
app.mixin({
    // 在任何组件 dom准备好的时候 打印一句话
    methods: {
        say() {
            console.log(this.$el,'dom准备好了');
        }
    },
    mounted() {
        this.say();
    }
})
app.mount('#app');

2、局部混入

// mixins.js
// 配置对象
export const followMixin =  {
    data () {
      return {
        loading: false
      }
    },
    methods: {
      followFn () {
        this.loading = true
        // 模拟请求
        setTimeout(()=>{
          // 省略请求代码
          this.loading = false
        },2000)
      }
    }
}
<template>
  <div class="container1">
    <h1>
      作者:周杰伦
      <a href="javascript:;" @click="followFn">{{ loading ? "请求中..." : "关注" }}</a>
    </h1>
    <hr />
    <Son />
  </div>
</template>
<script>
import Son from "./Son.vue";
import { followMixin } from "./mixins.js";
export default {
  name: "App",
  components: {
    Son,
  },
  mixins: [followMixin],
};
</script>



相关推荐

一、概述 在vue2中,data函数里返回的值直接为响应式,但在vue3中我们需要使用一些函数才能达到这个效果。 setup函数中拿不到vue的this。 二、常用函数 <template> <d

一、computed和watch应用场景 1、computed computed拥有缓存属性,擅长的处理的场景是一个数据受多个数据影响。 2、watch 擅长处理的场景是一个数据影响多个数据,另外可以

一、概述 <script setup> 是在单文件组件(SFC)中使用组合式API的编译时语法糖,解决Vue3.0中setup需要频繁将声明的变量、函数以及import引入的内容通过return向外

<script> export default { setup() { const func1= () => { console.log("func1");

一、概述 在vue3中没有$refs这个对象,可以使用如下方法 <template> <div><input type="text" ref="txt1" value="hello" /></div>

一、概述 watchEffect和watch都是监听器,但在写法和使用上有所区别。 watch- 显式指定依赖源,依赖源更新时执行回调函数 watchEffect - 自动收集依赖源,依赖源更新时重

一、概述 在 Vue 3 中,shallowRef 是一种用于创建浅层响应式引用的 API。与 ref 不同,shallowRef 只会对其引用的值进行浅层监听,而不会递归地使对象的内部属性也成为响应

1、安装依赖 npm install svg-sprite-loader --save-dev 2、配置build文件夹中的webpack.base.conf.js 3、在src/component

ref被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的$refs对象上。如果在普通的DOM元素上使用,引用指向的就是DOM元素,如果用在子组件上,引用就指向组件实例。 <!-- `vm.$

https://cn.vuejs.org/v2/api/#vm-options