Vue3 学习 其他的 CompositionAPI 与其他改进

2022.06.08

shallowReactive与shallowRef

shallowReactive()相对于Reactive()来说,只处理最外层属性的响应式(浅响应式)。shallowRef()相对于Ref()来说,只处理基本数据类型的响应式,不处理对象类型。

作用在于节约资源,提高性能。

readonly与shallowReadonly

readonly()让一个响应式的数据变为只读。shallowReadonly()只让一个响应式对象数据的最外层属性变为只读(浅只读)。

作用在于不希望数据被修改时。

toRaw与markRaw

toRaw()让一个由reactive生成的响应式对象变为普通对象。用于读取一个响应式对象对应的普通对象,对这个普通对象的操作不会引起页面的更新。

markRaw()标记一个对象,使其永远不会再成为响应式对象。用于标记有些第三方类库不被设置为响应式,或当渲染有些不可变数据源的大列表时,跳过响应式转换,以提高性能。

customRef

customRef()可以创建一个自定义的ref,并使用track()和trigger()对其依赖项的跟踪和更新触发进行显式控制。

案例:实现防抖效果

 <template>
  <input type="text" v-model="keyword" />
  <h3>{{ keyword }}</h3>
</template>

<script>
import { ref, customRef } from 'vue'
export default {
  name: 'Demo',
  setup() {
    // let keyword = ref('hello') //使用Vue准备好的内置ref
    
    //自定义一个myRef
    function myRef(value, delay) {
      let timer
      //通过customRef去实现自定义
      return customRef((track, trigger) => {
        return {
          get() {
            track() //告诉Vue这个value值是需要被“追踪”的
            return value
          },
          set(newValue) {
            clearTimeout(timer)
            timer = setTimeout(() => {
              value = newValue
              trigger() //触发,告诉Vue去更新界面
            }, delay)
          },
        }
      })
    }
    
    let keyword = myRef('hello', 500) //使用自定义的ref
    
    return {
      keyword,
    }
  },
}
</script>

provide与inject

配合使用可以实现祖代与后代之间的数据通信。祖代组件使用provide()来提供数据,后代组件使用inject()来接收数据。

img

在祖代组件中:

setup(){
  let car = reactive({name:'奔驰',price:'40万'})
  provide('car',car) //提供数据
}

在后代组件中:

setup(){
  const car = inject('car')
  return {car}
}

响应式数据的判断

isRef():检查一个值是否为ref对象。

isReactive():检查一个值是否为由reactive()创建的响应式代理。

isReadonly():检查一个对象是否为由readonly()创建的只读代理。

isProxy():检查一个对象是否为由reactive()或readonly()创建的对象。


以下是Vue3中的部分其他改动的地方,更完整的改动应当参考Vue3官方文档

teleport组件

teleport可以将html结构移动到指定位置。位置可以是DOM元素名,也可以是css选择器名。

<teleport to="移动位置">
  <div v-if="isShow" class="mask">
    <div class="dialog">
      <h3>我是一个弹窗</h3>
      <button @click="isShow = false">关闭弹窗</button>
    </div>
  </div>
</teleport>

suspense组件

suspense可以在等待异步组件的时候渲染一些额外的内容,让用户体验更好。

异步引入组件:

import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))

使用suspense包裹组件的html结构,并配置好default和fallback:

<template>
  <div class="app">
    <h3>我是App组件</h3>
    
    <Suspense>
      <!-- 默认要被显示的组件结构 -->
      <template v-slot:default>
        <Child/>
      </template>
      <!-- 等待时额外渲染出来的结构 -->
      <template v-slot:fallback>
        <h3>加载中.....</h3>
      </template>
    </Suspense>
    
  </div>
</template>

全局API的转移

在Vue2中的全局API和配置等,Vue3都调整到应用实例app身上了。

2.x 全局API(Vue) 3.x 实例API (app)
Vue.config.xxxx app.config.xxxx
Vue.config.productionTip 移除
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use
Vue.prototype app.config.globalProperties

data选项

Vue3中data选项应当始终被声明为一个函数了。

动画中过渡的类名

Vue3中将类名v-enter改为了v-enter-from,更加语义化。

.v-enter-from,
.v-leave-to {
  opacity: 0;
}

.v-leave-from,
.v-enter-to {
  opacity: 1;
}

移除keycode及native修饰符

Vue3不再支持keyCode作为v-on事件修饰符了,也不再支持config.keyCodes自定义按键别名了。

同时也不再支持native作为v-on事件修饰符了。在父组件中给子组件绑定事件,若为自定义事件则需在子组件中用emits接收,若为原生事件则不需要。

在父组件中给子组件绑定原生与自定义事件:

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

在子组件中仅接收自定义事件:

export default {
  emits: ['close']
}

移除filter过滤器

Vue3官网说:

过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。