Vue3.x新特性总结及与vue2.x的对比

一.Vue3.x与Vue2.x的区别

1.OptionsApi 和 CompositionApi的区别

须知:你仍然可以在Vue3.x中使用vue2的选项式Api写法,但我更建议你选择最新的组成式Api写法

OptionsApi - Vue2.x - 选项式Api
1.限制了自由度,必须按照规定来书写代码,如props,methods,data,computed,watch,各司其职,禁止越界
2.上下文必须使用this
3.生命周期包含beforeCreated()和Created()

CompositionApi - Vue3.x - 组成式Api
1.将代码打碎,允许在setup()函数中自由书写,使代码的分割感进一步降低
2.没有this,统一使用setup()函数中的context参数,由原来的this.getData => context.getData
3.生命周期被setup()入口给替代
4. Tree-Shaking 的目的,使用到什么就引入什么,最后打包也只打包用到的 api

示例:
content上下文
在这里插入图片描述

2.生命周期的变化

整体来看其实变化不大,使用setup代替了之前的beforeCreate和created,其他生命周期名字有些变化,功能都是没有变化的
在这里插入图片描述

3.template模板支持多个根标签

  • 由原有的单一根标签调整为支持多个根标签,减少无用代码,增加代码自由度!
  • 之所以支持多个根标签,是因为底层改为了Fragment组件进行包裹
//Vue2.x写法
<template>
	<div class="name">
		<p></p>
		<p></p>
	</div>
</template>
//Vue3.x
<template>
	<div class="name"></div>
	<div class="name2"></div>
	<div class="name3"></div>
</template>

4.Route获取页面实例与路由信息

Vue2.x

  • 通过this获取router实例
export default{
    
    
  mounted() {
    
    
    this.getRouter();
  },
  methods: {
    
    
    getRouter() {
    
    
      console.log(this.$route);
      console.log(this.$router);
    },
  },
}

Vue3.x

  • 第一种 通过使用 getCurrentInstance 方法获取当前组件实例

import {
    
     getCurrentInstance } from "vue";
export default {
    
    
  setup(props, context) {
    
    
    const {
    
     ctx } = getCurrentInstance();
    console.log(ctx.$router.currentRoute.value);
  },
};
  • 第二种通过userRoute和userRouter
import {
    
     useRoute, useRouter } from "vue-router";
export default {
    
    
  setup(props, context) {
    
    
    const currRoute = useRoute();
    const currRouter = useRouter();

    console.log(currRoute);
    console.log(currRouter);
  },
};

5.Vuex状态管理

  • api没有显著变化,
  • 创建实例的方式改变,Vue2.x为new Store , Vue3.x为createStore
//Vue2.x 中创建 store 实例
export default new Vuex.Store({
    
    
   // ... 
})

//Vue3.x
import Vuex from 'vuex'

export default Vuex.createStore({
    
    
  state: {
    
    
    count: 0
  },
  mutations: {
    
    
    ADD (state) {
    
    
      state.count++
    }
  },
  actions: {
    
    
    add ({
     
      commit }) {
    
    
      commit('ADD')
    }
  },
  modules: {
    
    
  }
})

Vue3.x组件中使用 - 两种方式

  • 第一种方式
<template>
  <div class="home">
    <p>{
    
    {
    
    count}}</p>
    <button @click="add">增加</button>
  </div>
</template>

<script>
import {
    
     computed } from 'vue'
import {
    
     useStore } from 'vuex'
export default {
    
    
  setup () {
    
    
    const store = useStore()
    const count = computed(() => store.state.count)

    const add = () => {
    
    
      store.dispatch('add')
    }
    
    return {
    
    
      count,
      add
    }
  }
}
</script>
  • 第二种方式: 在当前组件上下文中获取 store
import {
    
    getCurrentInstance} from 'vue'
// ...
const store = getCurrentInstance().ctx.$store

6.响应式对象函数 ref和reactive

export default{
    
    
	setup(){
    
    
		const count=ref(0);
		const state=reactive({
    
    
			count:0
		})
	}
}

ref

  • ref更偏向于定义单个变量,而reactive更偏向定义对象。
  • ref修改数据需要使用这样count.value=xxx 的形式,而reactive只需要state.count=xxx 这样来使用
  • ref相当于内部封装了reactive
  • ref 就当作简单的双向绑定变量 toRef 就是把不是响应式的对象转化成响应式
  • 模板在取值是可以直接使用{ {count}}的

reactive

  • reactive 内部是可以使用计算属性等各种方法,它只是把数据双向绑定了而已
  • reactive 后return的数据最好是用toRefs 转化一下
  • 跟 ref 混合使用时候可以用isRef 判断类型

7.监听属性watch和watchEffect的区别

  • watch需要指定监听的属性(参数), vue3.x中新增watchEffect,不需要指定监听的属性(参数),自动收集响应式属性
  • watch可以获取到新值与旧值(更新前的值),而 watchEffect 是拿不到的
  • watch起初就指定了依赖,初始化时不会执行,依赖发生变化时才会执行
    而watchEffect 在初始化时就会执行一次,用来收集依赖,当依赖变化后,watchEffect 还会再次执行
  • watch 和 watchEffect 都无法监听未被双向绑定的属性
  • watch 可以直接监听 ref 和 reactive 绑定的对象,watchEffect 不可以(ref的值要.value,reactive的值要具体到内部属性),只会执行第一次

总结:通过比较两属性的不同点根据具体需求合理的使用
1.如果需要组件初始化时执行,则用watchEffect
2.如果需要获取新值旧值,则使用watch

在这里插入图片描述

在这里插入图片描述

8.计算属性computed

  • 第一种不允许修改值,会提示警告: 计算属性不允许修改
  • 第二种允许修改值
    在这里插入图片描述

9. 支柱Props的使用变化

  • Vue2.x中使用
exprot default {
    
    
    props: {
    
    
        title: String
    },
    mounted() {
    
    
        console.log(this.title);
    }
}
  • Vue3.x中使用
//通过setup中的内置参数进行调用,舍弃了之前的this调用方式
exprot default {
    
    
    props: {
    
    
        title: String
    },
    //props 组件传入的属性
    setup(props,context) {
    
    
        console.log(props.title) // 响应式
    }
}

10.混入Mixins的变化

  • Vue2.x 中mixin模式表面上看起来很安全。但是它通过合并对象来共享代码,给代码无形中增加了脆弱性,代码来源不清晰、方法属性等冲突, 并且掩盖了推理功能的能力,因此成为一种反模式。
// vue页面中引入,该方法会将Mixins中的所有方法和属性一并引入
import mixin from 'mixin.js'
export default{
    
    
	data(){
    
    },
	mixins: [mixin]
}
  • Vue3.x 中Composition API最聪明的部分是,它允许Vue依靠原生JavaScript中内置的保障措施来共享代码,比如将变量传递给函数和模块系统,只使用需要调用的部分!
// vue页面中引入
import mixin from 'mixin.js'
//第一种写法 - 利用ES6解构写法,只引用需要的部分
export default{
    
    
	setup(){
    
    
		const {
    
     count, plusOne, hello } = mixin()
		hello()
		console.log(count.value, plusOne.value)
	}
}

// 第二种写法 - 调用组件中的局部变量
export default {
    
    
  setup () {
    
    
    // 某个局部值的合成函数需要用到
    const myLocalVal = ref(0);
    // 它必须作为参数显式地传递
    const {
    
     ... } = mixin(myLocalVal);
  }
}

11.自定义指令Custom Diretctives

  • 摘自官方文档 自定义指令
  • 自定义指令顾名思义即自行创造如v-html , v-bind , v-on等指令方便调用
    在这里插入图片描述

12.传送门 Teleport

13.父子组件传值

  • 在向父组件传回数据时,如使用的自定义名称,如backData,则需要在emits中定义一下,否则会在控制台中报 emits option 警告
<template></template>
export default{
    
    
	emits:['backData'],
	setup(props,{
     
     emit}){
    
    
		function back(){
    
    
			emit('backData');
		}
	}
}

二.小知识

1.基于Vue3编码是否全部使用TypeScript编码?

1 、对于业务经常变动的业务项目,不适合用 TypeScript,因为快速才是此类需求最重要的。
2 、对于工具类 /基础设施类项目,最好上 TypeScript 。

2.defineComponent的使用时机

根据编写代码使用的语言方式不同,选择合适的模块

  1. 如果用TypeScript,导出时则必须要用 defineComponent,这俩是配对的,为了类型的审查正确,如图一
  2. 如果是JavaScript编码,则无需该函数,如图二
    在这里插入图片描述在这里插入图片描述

3.script和script setup的使用区别

  • 加上setup后的写法后,通过export导出属性或方法
<template>
  <button @click="inc">{
    
    {
    
     count }}</button>
</template>

<script setup>
  import {
    
     ref } from 'vue'

  const count = ref(0)
  const inc = () => count.value++
</script>
  • 不加setup后的写法,则需要将属性或方法return出去,类似于vue2.x中data()中的return
import {
    
     ref } from 'vue'

export default {
    
    
  setup() {
    
    
    const count = ref(0)
    const inc = () => count.value++

    return {
    
    
      count,
      inc,
    }
  },
}

4. Object.defineProperty(Vue2)和Proxy(Vue3)的响应式区别

Vue2.x Object.defineProperty

  • 只能劫持对象属性的getter和setter操作,数据变化时需要遍历对象的所有属性,如data,props等,消耗较大
  • 不支持Set/Map、class、数组等类型
  • 无法检测到新加或删除属性,不具备响应式,需要手动调用this.$set进行更新
  • Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应,也无法监听到push等方法,vue中重写了这些方法来增加setter
const data= {
    
    
    name: 'xiaoming',
    sex: '男'
}
// 遍历对象,对其属性值进行劫持
Object.keys(data).forEach(key => {
    
    
  let val = data[key]
  Object.defineProperty(data, key, {
    
    
    enumerable: true, // 该属性可被枚举
    configurable: true, // 该属性可以被删除以及属性描述符可以被改变
    get () {
    
    
      console.log(`属性值${
      
      data}当前值为${
      
      val}`)
      return val
    },
    set (newValue) {
    
    
      console.log(`监听到属性值${
      
      data}${
      
      val}变为${
      
      newValue}`)
      val = newValue
    }
  })
});
 
data.name // 属性值name当前值为zhangsan
data.name = 'lisi' // 监听到属性值name由zhangsan变为lisi
data.age // 属性值age当前值为18
data.age = 25 // 监听到属性值age由18变为25

Vue3.x Proxy(ES6)

  • 可以劫持整个对象
  • 对象新增属性可以实时响应式,可以检测到数组下标的变化
  • 因为Proxy是ES6新增的属性,有些浏览器还不支持,只能兼容到IE11
let obj = {
    
    
  a: 1,
  b: 2,
}
 
const p = new Proxy(obj, {
    
    
  get(target, key, value) {
    
    
    if (key === 'c') {
    
    
      return '我是自定义的一个结果';
    } else {
    
    
      return target[key];
    }
  },
 
  set(target, key, value) {
    
    
    if (value === 4) {
    
    
      target[key] = '我是自定义的一个结果';
    } else {
    
    
      target[key] = value;
    }
  }
})
 
console.log(obj.a) // 1
console.log(obj.c) // undefined
console.log(p.a) // 1
console.log(p.c) // 我是自定义的一个结果
 
obj.name = '李白';
console.log(obj.name); // 李白
obj.age = 4;
console.log(obj.age); // 4
 
p.name = '李白';
console.log(p.name); // 李白
p.age = 4;
console.log(p.age); // 我是自定义的一个结果

5. env环境变量配置

  • 项目根目录新建 .env.development 和.env.production
  • 自定义的环境变量必须以 VITE_APP开头
  • package.json 中添加对应后缀
  • 页面中调用 import.meta.env.VITE_APP_BASE_API;
    在这里插入图片描述
    在这里插入图片描述
console.log(import.meta.env);

6. 初始化data数据

Vue2.x

Object.assign(this.$data, this.$options.data());

Vue3.x

 const initState = () => {
    
    
      return {
    
    
        a: 1
      }
    }
 const state = reactive(initState())
    
 const resetState = () => {
    
    
      Object.assign(state, initState())
    }

扩展阅读

如您已了解完Vue3.x的新特性,则推荐您看以下文章,方便您快速入手Vue3项目

猜你喜欢

转载自blog.csdn.net/r657225738/article/details/115551368