likes
comments
collection
share

Vue3.0全家桶最全入门指南 - 3.x跟2.x的其他差异 (4/4)

作者站长头像
站长
· 阅读数 26

本系列文章目录

四、3.x跟2.x的其他差异

ctx属性

对于网上一些其他文档使用ctx.$routerctx.$store访问router和store的应该小心避坑,注意开发环境和生产环境的差别

vue3.x 开发环境 ctx

开发环境的ctx,可以看到$router$store、声明的变量和方法等

Vue3.0全家桶最全入门指南 - 3.x跟2.x的其他差异  (4/4)

vue3.x 生产环境 ctx

生产环境的ctx$router$store没有了,其他属性也都没有了,不能通过ctx.$routerctx.$store访问router和store,因此ctx可以说对我们没有用,应该避免在代码中使用ctx

Vue3.0全家桶最全入门指南 - 3.x跟2.x的其他差异  (4/4)

执行顺序

vue3.x中会先执行setup方法,再执行兼容2.x的其他方法,比如datacomputedwatch等,

并且在setup执行过程中,无法访问data中定义的属性,因为此时还未执行到data方法

mount挂载

使用mount挂载的时候

2.x会使用挂载元素的outerHTML作为template,并替换挂载元素

3.x会使用挂载元素的innerHTML作为template,并且只替换挂载元素的子元素

this.$el、reactive refs、template refs

2.x可以在组件挂载之后通过this.$el访问组件根元素

3.x去掉this,并且支持Fragment,所以this.$el没有存在的意义,建议通过refs访问DOM

当使用组合式 API 时,reactive refstemplate refs 的概念已经是统一的。为了获得对模板内元素或组件实例的引用,我们可以像往常一样在 setup() 中声明一个 ref 并返回它

使用reactive refs和template refs

<template>
  <div ref="root"></div>
</template>

<script>
  import { ref, onMounted, getCurrentInstance } from 'vue'

  export default {
    setup() {
      const vm = getCurrentInstance()
      const root = ref(null)

      onMounted(() => {
        // 在渲染完成后, 这个 div DOM 会被赋值给 root ref 对象
        console.log(root.value) // <div/>
        console.log(vm.refs.root) // <div/>
        console.log(root.value === vm.refs.root) // true
      })

      return {
        root
      }
    }
  }
</script>

在v-for中使用

<template>
  <div v-for="(item, i) in list" :key="i" :ref="el => { divs[i] = el }">
    {{ item }}
  </div>
</template>

<script>
  import { ref, reactive, onBeforeUpdate } from 'vue'

  export default {
    setup() {
      const list = reactive([1, 2, 3])
      const divs = ref([])

      // 确保在每次变更之前重置引用
      onBeforeUpdate(() => {
        divs.value = []
      })

      return {
        list,
        divs
      }
    }
  }
</script>

setup返回普通对象

setup返回普通对象的时候,会跟reactive对象一样,具备响应式,执行下面这段代码后会发现普通对象obj1.cnt也具有响应式了,虽然这样可以行得通,但是为了可读性,防止不了解这个特性的同学误解为非响应式的,建议还是通过reactive包一下。

<template>
  <div>{{ obj1.cnt }}</div>
  <div>{{ obj2.cnt }}</div>
</template>

<script>
import { reactive } from 'vue'

export default {
  setup () {
    // 普通对象
    const obj1 = {
      cnt: 1
    }
    // 代理对象
    const obj2 = reactive({
      cnt: 1
    })
    setInterval(() => {
      obj1.cnt++
      obj2.cnt++
    }, 5000)
    
    return {
      obj1,
      obj2
    }
  }
}
</script>

directive指令

vue3.x对指令的生命周期钩子进行了改造,改造后更像3.x普通vue组件的钩子,更方便记忆

// vue2.x
export default {
  name: 'YourDirectiveName',
  bind(el, binding, vnode, oldVnode) {},
  inserted(...) {},
  update(...) {},
  componentUpdated(...) {},
  unbind(...) {}
}

// vue3.x
export default {
  beforeMount(el, binding, vnode, oldVnode) {},
  mounted(...) {},
  beforeUpdate(...) {},
  updated(...) {},
  beforeUnmount(...) {},
  unmounted() {...}
}

render方法修改

vue、react都提供了render方法渲染html模板,直接使用render方法的还是比较少,毕竟有templateJSX,对于确实需要自定义render方法渲染模板内容的,具体变动如下:

// vue2.x
export default {
  render(h) {
    return h('div')
  }
}

// vue3.x
import { h } from 'vue'
export default {
  render() {
    return h('div')
  }
}

3.x中移除的一些特性

取消KeyboardEvent.keyCode

在vue3.x中,给keyup事件配置一个指定按钮的keyCode(数字)将不会生效,但是依然可以使用别名,例如:

// 无效
<input @keyup.13="handler" />
// 有效
<input @keyup.enter="handler" />

移除 on,on,on,off 和 $once方法

在Vue2.x中可以通过EventBus的方法来实现组件通信

// 声明实例
var EventBus = new Vue()
Vue.prototype.$globalBus = EventBus
// 组件内调用
this.$globalBus.$on('my-event-name', callback)
this.$globalBus.$emit('my-event-name', data)

在vue3.x中移除了 $on$off等方法,而是推荐使用mitt方案来代替:

// 声明实例
import mitt from 'mitt'
const emitter = mitt()
// 组件内调用
// listen to all events
emitter.on('*', (type, e) => console.log(type, e))
emitter.on('my-event-name', callback)
emitter.emit('my-event-name', data)
// clearing all events
emitter.all.clear()

移除filters

在vue3.x中,移除了组件的filters项,可以使用methods的或者computed来替代

移除inline-template

在Vue2.x中,在父组件引入子组件时,会用到inline-template来使子组件的内容也得到展示,参考这里,例如:

<my-component inline-template>
  <div>
    <p>These are compiled as the component's own template.</p>
    <p>Not parent's transclusion content.</p>
  </div>
</my-component>

在Vue3中,这个功能将被移除,目前inline-template使用的并不多,这里就不再过多讲解

后话

虽然vue3.0已经进入rc版本,但是就算vue3.0正式版出来了,3.0相关的生态更新肯定需要一段时间,比如element-uiant-designiview等框架,还有其他开源组件,如果想在正式项目使用的话还是要仔细评估风险,个人建议对vue开源没有依赖的可以先上手vue3.0,有依赖的还是再等一段时间,等生态都支持vue3.0了再去升级,另外对现有项目升级还需要评估工作量。

参考文章

github.com/vuejs/rfcs

composition-api.vuejs.org/zh/api.html

本系列文章目录