vue3基础之语法、核心API

767 阅读3分钟

本文基于vue3.2,主要写了 vue3新特性和与vue2相比写法用法有差距的地方,包括响应式Api、composition Api、setup语法糖等。和vue2用法相同的部分模板语法、列表渲染、条件判断等,可以查看官网v3.cn.vuejs.org/

vue3亮点

  1. 比vue快近2倍
  2. Tree Shaking 按需编译代码
  3. Composition API 更好的逻辑复用与代码组织
  4. 更好的类型推导(typeScript支持)

应用入口

  1. createApp() 函数创建应用实例,需要在vue中导入函数
  2. mount() 函数挂载应用根组件
// 参考main.js
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
  1. 通过链式操作使用插件
import router from './router/index'
import ElementPlus from '@/plugins/element-plus.js';
// ...
createApp(App).use(router).use(ElementPlus).mount('#app')

响应性API

  1. reactive:对象响应式 接收⼀个普通对象然后返回该普通对象的响应式代理。等同于 vue 2.x 的 Vue.observable()
import { reactive } from 'vue'
const obj = reactive({ count: 0 })
  1. ref :单值响应式 接受⼀个参数值并返回⼀个响应式Ref 对象。Ref 对象拥有⼀个指向内部值的单⼀属性 value 。
const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

在模板中使用可以直接 {{count}},在模板中会自动解包。只有访问嵌套的 ref 时需要在模板中添加 .value

  1. toRefs方法 把⼀个响应式对象转换成普通对象,该普通对象的每个属性都是⼀个Ref。
const state = reactive({
    foo: 1,
    bar: 2,
})
const stateAsRefs = toRefs(state)

使用ES6结构响应式对象时,解构出来的 property 的响应性都会丢失。这时可以使用toRefs方法防止响应式丢失。

const book = reactive({
  author: 'Vue Team',
  year: '2020',
  title: 'Vue 3 Guide',
  description: 'You are reading this book right now ;)',
  price: 'free'
})

// let { author, title } = book  // 这样解构响应式会丢失
let { author, title } = toRefs(book)

title.value = 'Vue 3 Detailed Guide' // 我们需要使用 .value 作为标题,现在是 ref
console.log(book.title) // 'Vue 3 Detailed Guide'

tips 上面一些API使用时都需要先import导入。

组合式API

vue2中使用选项式API(options Api),vue3使用组合式PAI(composition Api)。组合式API ⼀组低侵⼊式的、函数式的 API,使得我们能够更灵活地「组合」组件的逻辑。避免了选项式API中逻辑代码块反复横跳的问题。

1. setup

一个组件选项,在组件被创建之前props 被解析之后执行。它是组合式 API 的入口。setup中不可以使用this,也没必要使用。

import { onMounted } from 'vue'
export default {
  components: { Temp },
  props: {
    user: {
      type: String,
      required: true
    }
  },
  setup(props) {
    console.log(props) // { user: '' }
    // 生命周期钩子
    onMounted(() => {
      console.log('Component is mounted!')
    })
    return {} // 这里返回的任何内容都可以用于组件的其余部分
  }
  // 组件的“其余部分”
}

vue3.2版本以前一些API、生命周期函数都要写在setup方法中。从vue3.2版本新增了一个setup的语法糖<script setup>,使用这个语法糖就不必写setup方法了 。

2. <script setup>语法糖

相比于普通的 <script> 语法,它具有更多优势:

  • 更少的样板内容,更简洁的代码。
  • 能够使用纯 Typescript 声明 props 和抛出事件。
  • 更好的运行时性能 (其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理)。
  • 更好的 IDE 类型推断性能 (减少语言服务器从代码中抽离类型的工作)。

下面是如何使用它:

  • 要使用这个语法,需要将 setup attribute 添加到 <script> 代码块上:
<script setup>
    const msg = 'hello world!';
</script>

里面的代码会被编译成组件 setup() 函数的内容。这意味着与普通的 <script> 只在组件被首次引入的时候执行一次不同,<script setup> 中的代码会在每次组件实例被创建的时候执行

  • 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用:
<template>
    <p> {{ msg }} </p>
</template>
  • 响应式
<script setup>
const count = ref(0)
function addcount() {
  count.value++
}
</script>
  • 使用组件
<template>
   <Foo />
</template>
<script setup>
    import Foo from './components/Foo.vue'
</script>

3. defineProps 和 defineEmits

在 <script setup> 中必须使用 defineProps 和 defineEmits API 来声明 props 和 emits ,它们具备完整的类型推断并且在 <script setup> 中是直接可用的:

子组件

<template>
  <div class="box">
    <p>我是Foo组件</p>
    <button @click="add">{{ num }}</button>
  </div>
</template>

<script setup>
const props = defineProps({
  num: Number,
})
// console.log(props)
const emits = defineEmits(['add'])
// console.log(emits)

function add() {
  emits('add')
}
</script>

父组件

<Foo :num="num" @add="add" />

<script setup>
const num = ref(100)
const add = () => {
  num.value++
}
</script>

defineProps 和 defineEmits 都是只在 <script setup> 中才能使用的编译器宏$emit等方法可以直接在模板中使用,但是不能直接在 <script setup>使用

4. 生命周期

可以通过直接导入 onX 函数来注册生命周期钩子:

<script setup>
import { onMounted, onUpdated } from 'vue'

onMounted(() => {
  console.log('Component is mounted! -------------')
})
onUpdated(() => {
  console.log('updated! ----------------num', num.value)
})
</script>

选项式 API 的生命周期选项和组合式 API 之间的映射

  • beforeCreate -> 使用 setup()
  • created -> 使用 setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeUnmount -> onBeforeUnmount
  • unmounted -> onUnmounted
  • errorCaptured -> onErrorCaptured
  • renderTracked -> onRenderTracked
  • renderTriggered -> onRenderTriggered
  • activated -> onActivated
  • deactivated -> onDeactivated

计算属性和侦听器

  • 计算属性computed 返回一个不可手动更改的ref对象。
const plusOne = computed(() => count.value + 1);
plusOne.value++; // error
  • 侦听器watch 帧听单个数据源
// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)

// 直接侦听ref
const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})

watch也可以使用数组帧听多个数据源

watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {})
  • 副作⽤侦听器 watchEffect

⽴即执⾏传⼊的⼀个函数,并收集响应式的依赖,当依赖变更时重新运⾏该函数。

watchEffect(() => console.log(count.value)) // 初始执行打印出 0

本文demo地址 github.com/kongcodes/v…

从0开始vue3项目搭建