Vue2和Vue3在使用上的一些差异

202 阅读2分钟

1、语法上的一些变化

① vue3的template支持多个根标签,vue2不支持

② v-if与v-for的优先级对比 vue2在一个元素上同时使用v-if和v-for时,v-for会优先作用
vue3在一个元素上同时使用v-if和v-for时,v-if会优先作用 ③ v-bind合并行为

<!-- vue2中如果一个元素同时定义了v-bind="object"和一个相同的单独的property,
那么这个单独的property总是会覆盖object中的绑定 -->
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="red"></div>

<!-- vue3则是由声明绑定的顺序决定 -->
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="blue"></div>

<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>

④ v-model语法糖机制改变 vue2中v-model在表单元素使用上使用属性和表单事件,是固定不变的

  • 只用于表单元素,默认属性名和事件名是valueinput
  • 硬编码,不能扩展
<comp v-model="msg"></comp>
<!-- 等价于 -->
<comp :value="msg" @input="msg = $event"></comp>
// 示例:自定义input组件
Vue.component('custom-input', {
  props: {
    value: String,
  },
  template: `
    <input
      type="text"
      :value="value"
      @input="$emit('input', $event.target.value)"
    >
  `
})
// 示例:自定义count组件
Vue.component('custom-count', {
  model: {
    prop: 'v',  // default: value
    event: 'i'  // default: input
  },
  props: {
    v: Number
  },
  data(){
    return {
      count: this.v
    }
  },
  template: `<button @click="$emit('i', ++count)">+1</button>`
})

在线演示

vue3中v-model可以使用到任意组件,默认通过modelValue属性和自定义事件实现,不依赖于表单元素事件,且通过传递参数同一组件可以使用多个v-model

  • 默认实现不再依赖表单元素事件,可以用于任意组件,默认属性名和事件名是modelValueupdate:modelValue
  • 通过不同的参数v-model:foo指定属性名,修改体现在父组件中,同一组件可以绑定多个v-model
  • 不再依赖.sync修饰符
<custom-input v-model="msg"></custom-input>
<!-- 等价于 -->
<custom-input :model-value="msg" @update:model-value="msg = $event"></custom-input>

<!-- 更改v-model参数 -->
<custom-input v-model:mv="msg"></custom-input>

<custom-count v-model="count"></custom-count>
// 示例1:自定义input组件
// 实现1:默认参数
app.component('custom-input', {
  props: ['modelValue'],
  template: `
    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    >
  `
})
// 更改参数
app.component('custom-input', {
  props: ['mv'],
  template: `
    <input
      :value="mv"
      @input="$emit('update:mv', $event.target.value)"
    >
  `
})

// 实现2:使用input的v-model + computed(计算属性)
app.component('custom-input', {
  props: ['modelValue'],
  computed: {
    value: {
      get() {
        return this.modelValue;
      },
      set(v) {
        this.$emit('update:modelValue', v);
      },
    },
  },
  template: `
    <input v-model="value">
  `
})

// 示例2:自定义count组件
app.component('custom-count', {
  props: {
    modelValue: Number,
  },
  methods: {
    increment() {
      this.$emit('update:modelValue', ++this.modelValue);
    },
    decrement() {
      this.$emit('update:modelValue', --this.modelValue);
    },
  },
  template: `
    <button @click="increment">+1</button> ~ 
    <button @click="decrement">-1</button>
    <p>{{modelValue}}</p>
  `
})

在线演示

<!-- 多个v-model绑定 -->
<user-name v-model:first-name="firstName" v-model:last-name="lastName"></user-name>
app.component('user-name', {
  props: {
    firstName: String,
    lastName: String,
  },
  template: `
    <input 
      type="text"
      :value="firstName"
      @input="$emit('update:firstName', $event.target.value)">

    <input
      type="text"
      :value="lastName"
      @input="$emit('update:lastName', $event.target.value)">
  `
})

在线演示

⑤ v-for中的Ref数组 在vue2中,v-for绑定$refs将会自动生成一个refs的数组,但是在v-for中这种行为将会变得有歧义和不高效。
在vue3中,这种用法不会生效,因为vue3不会自动生成refs的数组。如果我们需要拿到多个refs组成的数组,那么就需要使用函数的方式手动去绑定。

<!-- vue2 -->
<div v-for="(item, index) in [4, 5, 6]" :key="'ref' + index" ref="itemRef">
  {{ item }}
</div>
export default {
  mounted () {
    console.log('ref:', this.$refs.itemRef)
  }
}
<!-- vue3 -->
<div v-for="(item, index) in [4, 5, 6]" :key="'ref' + index" :ref="setItemRef">
  {{ item }}
</div>
import { onBeforeUpdate, onMounted } from 'vue'
export default {
  setup () {
    let itemRefs = []
    const setItemRef = el => {
      itemRefs.push(el)
    }
    onBeforeUpdate(() => {
      itemRefs = []
    })
    onMounted(() => {
      console.log('ref:', itemRefs)
    })
    return {
      itemRefs,
      setItemRef
    }
  }
}

2、生命周期的变化

  • setup():开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
  • onBeforeMount():组件挂载到节点上之前执行的函数。
  • onMounted():组件挂载完成后执行的函数。
  • onBeforeUpdate():组件更新之前执行的函数。
  • onUpdated():组件更新完成之后执行的函数。