写点什么

Vue3 响应式语法糖

作者:程序员海军
  • 2023-04-16
    上海
  • 本文字数:2070 字

    阅读完需:约 7 分钟

Vue3 响应式语法糖

ref 与 响应式变量($ref)

响应式的变量可以像普通变量那样被访问和重新赋值,但这些操作在编译后都会变为带 .value 的 ref。响应式对象存在解构丢失响应性的问题,而 ref 需要到处使用 .value 则感觉很繁琐.


Vue 响应式语法糖 提供了一个 $ref() 方法是一个编译时的宏命令。它不是一个真实的、在运行时会调用的方法。而是用作 Vue 编译器的标记,表明最终的 变量需要是一个响应式变量

ref

ref 得通过 ref.value 访问, 有时会我们会忘记使用 .value 而丢失响应性。


const str = ref('测试')

onMounted(() => { console.log(str.value) //得通过ref.value 访问})
复制代码

$ref

通过 使用宏命令 $ 编译后都会变为带 .value 的 ref 。


const str = $ref('测试')

onMounted(() => { console.log(str) })
复制代码


每一个会返回 ref 的响应式 API 都有一个相对应的、以 $ 为前缀的宏函数。包括以下这些 API:



当启用响应性语法糖时,这些宏函数都是全局可用的、无需手动导入。但如果你想让它更明显,你也可以选择从 vue/macros 中引入它们:


import { $ref } from 'vue/macros'
let count = $ref(0)
复制代码

用 $() 将现存的 ref 转换为响应式对象

在某些场景中我们可能已经有了会返回 ref 的函数。然而,Vue 编译器并不能够提前知道该函数会返回一个 ref。那么此时可以使用 $() 宏来将现存的 ref 转换为响应式变量。


function myCreateRef() {  return ref(0)}
let count = $(myCreateRef())
复制代码

Props 响应式

两个痛点

失去响应性

和 ref 一样,都得通过 .value ,为了保持响应性,通过 props.x 来访问 prop ,得到的变量将不是响应式的、也不会更新。


const props = defineProps({    name: {      type: String,      default: () => '默认值'      },    data:{        type: Object,        required: true    }})


//访问props

props.nameprops.data
复制代码

定义默认值笨拙

当使用基于类型的 props 的声明时,无法很方便地声明这些 prop 的默认值。为此我们提供了 withDefaults() 这个 API,但使用起来仍然很笨拙。


interface MyProps {    phone: string | number,    name ?: string,    age : number | string
}const props = withDefaults(defineProps<MyProps>(),{ name:'海军', phone: '123123123123'})



props.nameprops.phone
复制代码

解决痛点

当 defineProps 与解构一起使用时,我们可以通过应用编译时转换来解决这些问题,类似于我们之前看到的 $()


interface MyProps {    phone: string | number,    name ?: string,    age : number | string
}

const { name = '海军', phone = 1234567, age = 28,} = defineProps<MyProps>()


watchEffect(() => { // 会在 props 变化时打印 console.log(name, phone, age) //海军 1234567 22})
复制代码

函数间传递时的响应性

参数形式传入函数 保持响应式

当 一个函数期望接收一个 ref 对象为参数时,我们可以这样写


$$() 的效果就像是一个转义标识:$$() 中的响应式变量不会追加上 .value。


const contents = $ref('测试')
const changeContent = (ctx: Ref<String>) => { console.log(ctx.value)}


watch($$(contents),(val)=> { changeContent($$(contents))})
复制代码

作为函数返回值

如果将响应式变量直接放在返回值表达式中会丢失掉响应性:



() 调用时任何对响应式变量的引用都会保留为对相应 ref 的引用, 这样保留了响应性。有点像 React Hooks 。


const useWindowData = () => {    const href = ref((window as Window).location.href)    return $$({        href    })}

const {href} = useWindowData()
复制代码

开启响应性语法糖

默认是关闭的状态,需要你显式选择启用。此外,以下列出的所有配置都需要 vue@^3.2.25。

Vite

  • 需要 @vitejs/plugin-vue@>=2.0.0

  • 应用于 SFC 和 js(x)/ts(x) 文件。在执行转换之前,会对文件进行快速的使用检查,因此不使用宏的文件应该不会有性能损失。

  • 注意 reactivityTransform 现在是一个插件的顶层选项,而不再是位于 script.refSugar 之中了,因为它不仅仅只对 SFC 起效。


// vite.config.jsexport default {  plugins: [    vue({      reactivityTransform: true    })  ]}
复制代码

Vue-CLi

  • 目前仅对 SFC 起效

  • 需要 vue-loader@>=17.0.0


// vue.config.jsmodule.exports = {  chainWebpack: (config) => {    config.module      .rule('vue')      .use('vue-loader')      .tap((options) => {        return {          ...options,          reactivityTransform: true        }      })  }}
复制代码

Webpack + Vue-loader

  • 目前仅对 SFC 起效

  • 需要 vue-loader@>=17.0.0


// webpack.config.jsmodule.exports = {  module: {    rules: [      {        test: /\.vue$/,        loader: 'vue-loader',        options: {          reactivityTransform: true        }      }    ]  }}
复制代码


发布于: 刚刚阅读数: 3
用户头像

🏆微信公众号:【前端自学社区】 2020-04-02 加入

🏅目前从事物流,铁路相关的前端全栈开发工作. 🏆 InfoQ 首批签约作者 🏆荣获2021/2022年度社区共建奖 😊个人微信: daxin261

评论

发布
暂无评论
Vue3 响应式语法糖_Vue 3_程序员海军_InfoQ写作社区