vue3 如何玩儿
本文最后更新于 400 天前,其中的信息可能已经有所发展或是发生改变。

VUE3:shit:

vue3 已经发布了快两年了,并且它的出现极大的改变了 vue 传统的写法、解决了 2.0 版本的一些疑难杂症. 3.0 的出现也预示了 vue 未来的发展是会慢慢朝着 hook 改变. 所以, 今天就来简单啰嗦几句吧.


VUE3 的优势

  • hook 设计, 紧追潮流, 朝着 react 奋起直追.
  • 从底层重新设计, 使用新的代理方式, 一定程度解决了上一版本的疑难杂症问题
  • typescript 的支持更加友好(以前版本对 typescript 的支持简直就是一坨 :shit:)
  • 响应式函数的引入, 让 vue3 充满活力, 更加灵活、更加方便的搞事情

安装

因为 typescript 的流行, 所以本文将采用 typescript 书写, 脚手架也将采用尤大亲自操刀设计、开发的 vite.

安装 VITE 项目

使用 yarn

$ yarn create vite

使用 NPM

$ npm create vite@latest

使用 PNPM

$ pnpm create vite

安装 VUE3 项目

# npm 6.x
npm create vite@latest my-vue-app --template vue

# npm 7+
npm create vite@latest my-vue-app -- --template vue

# yarn
yarn create vite my-vue-app --template vue

# pnpm
pnpm create vite my-vue-app --template vue

只需要按照提示一步步来就好, 如果不想这么麻烦, 可以直接拉取 Git 模板 ray-template 已经预设好了一些基础库.

进入正题

vue3.0 虽然保留了 options api 的写法, 但是这里不做讲解, 不上新的写法还不如不用. (这里只举例基础的、常用的函数)


书写方式

options api 虽然傻瓜式的书写, 但是有个很大的弊端就是, 很难抽离公共逻辑. 虽然官方提供了 mixin, 但是, 这个蠢东西有问题, 弊端很多. 有兴趣可以去看看这个玩意儿被如何吐槽的

  • Composition API

<template>
  <div class="demo">
    ref 响应式数据: {{ demoNumberRef }}
    demoState 响应式数据: {{ number }}
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, reactive, toRefs } from 'vue'

export default defineComponent({
  name: 'Demo',
  setup() {
    const demoNumberRef = ref(0)
    const demoState = reactive({
      number: 0,
    })

    return {
      demoNumberRef,
      ...toRefs(demoState),
    }
  },
})

setup 函数参数()

props 和标准的组件一致, 一个 setup 函数的 props 是响应式的,并且会在传入新的 props 时同步更新(不可解构)

context 上下文对象暴露了其他一些在 setup 中可能会用到的值(可以安全解构)

  • attrs: 透传 Attributes(非响应式的对象,等价于 $attrs)

  • slots: 插槽(非响应式的对象,等价于 $slots)

  • emit: 触发事件(函数,等价于 $emit)

  • expose: 暴露公共属性(函数)

2.x 版本不同的是, 3.0 的核心代码逻辑是写在 setup 函数中, 并且声明响应式数据的方法也有所不同, 采用响应式函数来声明(refreactive)
ref 函数声明数据需要通过 xxx.value 获取

reactive 接收一个 object 对象, 修改数据时以对象方法获取(不可解构)(demoState.number)

...toRefs(xxx) 可以将对象转换为响应式数据

  • Setup Sugar

<template>
  <div class="demo">
    ref 响应式数据: {{ demoNumberRef }} demoState 响应式数据:
    {{ demoState.number }}
  </div>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue'

const demoNumberRef = ref(0)
const demoState = reactive({
  number: 0,
})
</script>

setup sugar 虽然可以极大的简化书写代码, 但是因为他是由宏编译器实现的自动导出, 所以在使用 reactive 声明的变量在 template 中引用时需要 (demoState.number)方式获取

  • Options API

这里不做赘述, 写法与 2.x 大同小异

侦听

watch()

侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数

详细信息

watch() 默认是懒侦听的, 即仅在侦听源发生变化时才执行回调函数

侦听参数来源

  • 一个函数, 返回一个值
  • 一个 ref
  • 一个响应式对象
  • 或者是上述情况的组合

参数列表

第一个参数: 第一个参数是侦听器的源

第二个参数: 在发生变化时要调用的回调函数. 这个回调函数接受三个参数: 新值、旧值, 以及一个用于注册副作用清理的回调函数. 该回调函数会在副作用下一次重新执行前调用, 可以用来清除无效的副作用

都三个参数: 对象

immediate 在侦听器创建时立即触发回调. 第一次调用时旧值是 undefined

deep 如果源是对象,强制深度遍历,以便在深层级变更时触发回调

flush 调整回调函数的刷新时机

onTrack / onTrigger 调试侦听器的依赖

示例

侦听一个源

const demoNumberRef = ref(0)

watch(
  () => demoNumberRef,
  (data, preData) => {
    /* ... */
  },
)

侦听多个源

const fooRef = ref(0)
const demoRef = ref('hello')

watch([fooRef, demoRef], ([foo, demo], [prevFoo, prevDemo]) => {
  /* ... */
})

computed()

接受一个 getter 函数,返回一个只读的响应式 ref 对象. 该 ref 通过 .value 暴露 getter 函数的返回值. 它也可以接受一个带有 getset 函数的对象来创建一个可写的 ref 对象

示例

创建只读属性 ref

const count = ref(1)
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2

plusOne.value++ // 错误

创建可写的计算属性 ref

const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: (val) => {
    count.value = val - 1
  },
})

plusOne.value = 1
console.log(count.value) // 0

调试

const plusOne = computed(() => count.value + 1, {
  onTrack(e) {
    debugger
  },
  onTrigger(e) {
    debugger
  },
})

以上都是 vue3.0 最大的改动, 有了这些基础, 我们可以利用它们做一些有意思的东西了

利用响应式函数实现自定义 hook

仅仅是提供一个简单的思路! 写的烂, 别吐槽

实现 useWindowSize

思路, 首先声明 widthheight 两个响应式变量, 然后监听浏览器尺寸的变化, 最后返回一个响应式对象(包含: widthheight)

实现

  • 声明变量
const width = ref(0) // 浏览器宽度
const height = ref(0) // 浏览器高度
  • 获取浏览器尺寸
// 判断页面是否含有滚动条
const includeScrollbar = () =>
  document.body.scrollHeight >
  (window.innerHeight || document.documentElement.clientHeight)

// 获取浏览器尺寸, 然后赋值给: width、height
const update = () => {
  if (window) {
    if (includeScrollbar()) {
      width.value = window.innerWidth
      height.value = window.innerHeight
    } else {
      width.value = window.document.documentElement.clientWidth
      height.value = window.document.documentElement.clientHeight
    }
  }
}
  • 监听浏览器尺寸变化
window.addEventListener('resize', update)
  • 完整代码
const useWindowSize = () => {
  const width = ref(0)
  const height = ref(0)

  const includeScrollbar = () =>
    document.body.scrollHeight >
    (window.innerHeight || document.documentElement.clientHeight)

  const update = () => {
    if (window) {
      if (includeScrollbar()) {
        width.value = window.innerWidth
        height.value = window.innerHeight
      } else {
        width.value = window.document.documentElement.clientWidth
        height.value = window.document.documentElement.clientHeight
      }
    }
  }

  window.addEventListener('resize', update)

  return {
    width,
    height,
  }
}
  • 使用
const { width, height } = useWindowSize()

差不多大概思路就是如此, 利用响应式函数实现一些带有响应式的 hook

题外话

虽然官方建议 (事实上官方主推的 vue 的写法为模板语法) 采用模板语法进行开发, 但是模板语法的局限性还是太大, 尽管官方已经做了很多措施去补全, 但是写过 react 的会很不习惯这种方式. 所以, 这边建议采用 tsx 形式去开发. j(t)sx 是对于 js 的补充拓展, 所以它有很多模板不具有的特点, 其中最主要的就是灵活性, 配合上 vue3.0hook 能够更加灵活的开发项目

举个栗子 (仅针对 VITE 的使用)

  • 安装
# npm
npm install @vue/babel-plugin-jsx -D

# yarn
yarn add @vue/babel-plugin-jsx -D
  • 配置
/**
 *
 * - 打开 vite.config.j(t)s 文件
 * - 导入插件
 * - 注册插件
 * - [babel-plugin-jsx](https://github.com/vuejs/babel-plugin-jsx/tree/dev/packages/babel-plugin-jsx)
 */

import viteVueJSX from '@vitejs/plugin-vue-jsx'

plugins: [viteVueJSX()]
  • 使用
# 函数式组件
const App = () => <div></div>
# 实际使用
import { withModifiers, defineComponent } from 'vue'

const App = defineComponent({
  setup() {
    const count = ref(0)

    const inc = () => {
      count.value++
    }

    return {
      count,
      inc,
    }
  },
  render() {
    return <div onClick={withModifiers(this.inc, ['self'])}>{this.count}</div>
  },
})

vue-jsxreact-jsxclass 命名方式有点区别, vue-jsxclass. 具体的使用可以参考官方文档: babel-plugin-jsx

先就写这些, 改天继续更新. 白了个白
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇