阅读 2721

Vue 3.0.3 : 新增CSS变量注入以及最新的Ref提案

前言

在 Vue 3.0.3 版本中,Ref 语法糖已经实现,即使反对的人再多,尤雨溪也坚信这一语法糖会像 TypeScript 一样,用之前都觉得不好,用过之后说真香

所以不顾大家的反对,毅然决然的实现了这一需求,首先我们先来简单的回顾一下这个语法糖是干什么的:

Ref 语法糖

在之前,我们想要定义一个基本数据类型的响应式变量需要写成这样:

import { ref } from 'vue

const a = ref(0)
复制代码

当使用时要写成这样:

a.value = a.value + 10
// 或 a.value += 10
复制代码

这个value属性就很烦人了,因为咱们定义了一个数字0,给它取了个名字叫a,虽然咱们并不是写成了这样:

const a = 0
复制代码

但是在好多人的心目中,这个a就像上面这行代码一样,觉得它应该是基础类型,一方面不符合直觉,经常会忘记写.value。另一方面写起来也很麻烦,而且有时候需要写.value,有时候又不需要,比如用在<template>标签中时就不需要写.value,或者把ref赋值给reactive对象时:

import { ref, reactive } from 'vue'

const obj = reactive({
	a: ref(0)
})

// 这里不需要写成obj.a.value
console.log(obj.a)
复制代码

这无疑为我们增加了许多的心智负担,尤雨溪希望通过编译来实现像使用基础类型一样使用ref,写法如下:

// 声明一个变量(这个变量将会被编译成一个ref)
ref: count = 1

function inc() {
  // 该变量可以像普通变量那样使用
  count++
}

// 想要获取到原本的变量的话需要在变量前面加一个💲符号
console.log($count.value)
复制代码

Vue 3.0.3 CHANGELOG

通过 GitHub 中尤雨溪的 CHANGELOG 我们可以得知:

前半段写的修复的 Bug🐞 先暂且不提,咱们只看新的实验性特性有哪些:

  • compileScript inline render function mode
  • new script setup implementation
  • new SFC css varaible injection implementation
  • support kebab-case components in <script setup> sfc template
  • explicit expose API

这里面重点是第二条、第三条以及最后一条:

  • 实现了新的 <script setup>
  • 实现了新的单文件组件注入 CSS 变量
  • 控制导出的 expose API

那么新的<script setup>就包含了这个 Ref 语法糖

CSS 变量注入

那么这个CSS变量注入又是个什么鬼呢?

其实有篇文章已经把这个特性说的相当详细了:

《Vue超好玩的新特性:在CSS中引入JS变量》

总结起来就是:

  1. 以前在 JS 中的变量不能直接和 CSS 变量产生联系
  2. 现在可以在 <style> 标签中将 JS 变量与 CSS 变量进行关联
  3. 同时还具有响应性,比如改变了 JS 中 this.xxx 的值,同名的 CSS 变量也会随之改变,视图随之进行更新:
<template>
  <h1>Vue</h1>
</template>

<script>
export default {
  data () {
    return {
      opacity: 0
    }
  },
  mounted () {
    setInterval(_ => {
      this.opacity >= 1 && (this.opacity = 0)
      this.opacity += 0.2
    }, 300)
  }
}
</script>

<style vars="{ opacity }">
h1 {
  color: rgb(65, 184, 131);
  opacity: var(--opacity);
}
</style>
复制代码

运行结果: 可以看到有了这一特性,我们只需要改变同名的 JS 变量即可,这会让我们的项目更加的灵活,比如根据用户输入的合法颜色值来进行动态换肤等功能。

但这次更新改变了写法,在<style>标签中不需要再写vars="{ xxx }"了,在 CSS 代码中也不需要再写原生的 CSS 变量引用了(var(--xxx)),取而代之的是v-bind()这个函数,注意 ⚠️ 这个函数虽然跟 JS 里的v-bind很像,但只能用在 CSS 中,写法如下:

<template>
  <h1> shit! </h1>
</template>

<script>
export default {
  data () {
    return {
      color: 'yellow'
    }
  }
}
</script>

<style>
h1 {
  color: v-bind(color)
}
</style>
复制代码

如果是 JS 变量是xxx.xxx这种形式的话,比如这样:

export default {
  data () {
    return {
      font: {
      	weight: 100
      }
    }
  }
}
复制代码

那么 CSS 不能直接写成这样:

h1 {
	font-weight: v-bind(font.weight)
}
复制代码

而是需要用一对引号扩起来,类似于字符串的那种形式:

h1 {
	font-weight: v-bind('font.weight')
}
复制代码

expose API

那么这又是个什么鬼呢?

在 Vue 2 时期我们是通过 Options API 来写代码的,也就是说需要导出一个对象,对象的键无非就是那些耳熟能详的:

export default {
    data () {},
    mounted () {},
    computed: {},
    methods: {},
    // 省略若干 Options ...
}
复制代码

而现在新加了一个 expose:

export default {
    data () {},
    mounted () {},
    computed: {},
    methods: {},
    // 省略若干 Options ...
    expose: []
}
复制代码

这玩意是干嘛的呢?首先它的用法和 props 的数组形式差不多:

export default {
    data () {
    	return {
            x: 1,
            y: 2
        }
    },
    expose: [ 'x' ]
}
复制代码

这样的话在父组件中用 ref 获取子组件实例时,子组件身上只有x这个变量,y是获取不到的!

而在 Composition API 中的用法是这样的:

export default defineComponent((_, { expose }) => {
    expose({
      x: ref(1)
    })
    
    return {
      x: ref(2),
      y: ref(3)
    }
  }
})
复制代码

看!咱们这里有两个x,你们猜哪个x会被导出?

答案是如果有两个导出的变量的话,以 expose 导出的为准。

那么 Composition API 和 Options API 混合用法会是什么样的呢:

expotr default defineComponent({
  expose: ['x'],
  data () {
    return {
      x: 1
    }
  },
  setup (_, { expose }) {
    expose({
      y: ref(2)
    })
    
    return {
      y: ref(3),
      z: ref(4)
    }
  }
})
复制代码

正确答案是:

  • x = 1
  • y = 2
  • z = undefined

当然这些只在组件外起作用,组件内部还是能获取到z的,而且y也还是等于 3 的。

结语

Vue 现在已经不是我以前认识的那个 Vue 了,有些功能挺好挺实用,但有些……我都不知该说啥好了,大家是怎么看待现在已经改的面目全非了的 Vue 呢?

本文首发于公众号:《前端学不动》

往期精彩文章

文章分类
前端
文章标签