Vue3

初始化

创建一个项目

npm init vue@next

vue3的生命周期

setUp() { //  -> beforeCreate + created
  onBeforeMount(() => {})
  onMounted(() => {})
  onBeforeUpdate(() => {})
  onUpdated(() => {})
  onActivated(() => {}) // 被 <keep-alive> 缓存的组件激活时
  onDeactivated(() => {}) // 被 <keep-alive> 缓存的组件停用时
  onBeforeUnmount(() => {})
  onUnmounted(() => {})
  onErrorCaptured(() => {}) // 当捕获一个来自子孙组件的错误时被调用,返回 false 以阻止该错误继续向上传播
}

watch 侦听器的使用

import { watch } from 'vue'

watch(count, () => {
  console.log(count.value)
})
watch([count1, count2], () => {})
watch([count1, () => data.count2], () => {}) // 监听 reactive 包装的响应式对象使用函数式返回

const props = defineProps<{
  name: string
}>()

watch(() => props.name, () => {
  // 如果是监听一个对象属性,第一个参数需要函数的形式
})

计算属性

import { compute } from 'vue'

const single = ref(4)
const double = computed(() => {
  return single.value * 2
})

const double = computed({
  get: () => {
    return single.value * 2
  },
  set(value) {
    console.log(value)
  }
})

依赖注入

  • 父组件提供
<script setup>
import { provide } from 'vue'
const count = ref(0)
provide(/* 注入名 */ 'count', /* 值 */ count)
</script>
  • 应用级提供
import { createApp } from 'vue'

const app = createApp({})
app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
  • 接收
// 如果没有祖先组件提供 "message"
// `value` 会是 "这是默认值"
const value = inject('message', '这是默认值')

Teleport

将 teleport 包裹的元素传送到 指定 的元素中,例如 to=“body”

<template>
  <teleport to="#modal">
    <div v-if="isOpen" class="modal-box">
      <slot> <h2>this is a modal</h2> </slot>
      <button @click="closeModal">关闭</button>
    </div>
  </teleport>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
  props: {
    isOpen: Boolean
  },
  emits: {
    'close-modal': null // 这里要先声明emit
  },
  setup (props, context) {
    const closeModal = () => {
      context.emit('close-modal')
    }
    return {
      closeModal
    }
  }
})
</script>

通过 ref 获取 DOM 节点

dom 上的 ref 命名与 setup() 函数中 return 出来的变量名一致即可拿到 ref

<template>
 <div ref="drapdownRef" class="dropdown"/>
</template>
<script lang="ts" setup>
  import { ref } from 'vue'

  const drapdownRef = ref<null | HTMLElement>(null)
  if (drapdownRef.value) {
    console.log(drapdownRef.value)
  }
</script>

vue3 中的 template 要实现 ts 补全

// 在 vscode 的 setting.json 中添加
"vetur.experimental.templateInterpolationService": true

style 样式类使用变量 v-bind 语法糖

<template>
  <div class="test-bind">...</div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const color1 = ref('red')
</script>

<style scoped>
.test-bind{
  color: v-bind(color1);
}
</style>

这种写法其实是如下实现的一个语法糖:

<template>
  <div :style={'--custom-color': color1 } class="test-bind">...</div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const color1 = ref('red')
</script>

<style scoped>
.test-bind{
  color: var(--custom-color);
}
</style>

属性继承

<template>
  <div v-bind="$attrs">
</template>

$attrs 既可以将父组件传进来的属性传递给子组件,也可以将子组件的事件抛出到父组件