前端知识框架 前端知识框架
首页
基础
框架
插件
Node
地图
更多
前端须知
  • 分类
  • 标签
  • 归档

BestIdea

首页
基础
框架
插件
Node
地图
更多
前端须知
  • 分类
  • 标签
  • 归档
  • SVG图标组件
  • vue性能
  • vue中使用less全局变量
  • 路由懒加载
  • 生命周期
  • 双向绑定原理
  • 微信网页开发
  • 微信小程序开发(uni-app)
  • 微信小程序开发
  • 微信小程序入门
  • 0与3.0项目对比
  • 预渲染
  • 组件通信方式
  • Vue3.x组合式编程
    • 数据绑定
      • 基本使用
      • ts中使用
      • 原理Proxy
      • DOM更新nextTick
    • 计算属性
    • 生命周期函数
    • watch
    • 组件
    • 注册
      • props
      • 事件监听
      • 双向绑定v-model
    • 自定义指令
  • 从零搭建 vite+vue3+ts+pinia 框架
  • Vue-iClient3D-WebGL入门文档
  • Vite常用配置
  • 框架
郝东建
2023-04-06
目录

Vue3.x组合式编程

# 数据绑定

在 Vue 中,状态都是默认深层响应式的。这意味着即使在更改深层次的对象或数组,你的改动也能被检测到。

  1. reactive():创建一个响应式对象或数组(仅对对象类型有效)
  2. ref():创建可以使用任何值类型的响应式

区别

  • ref 定义:基本类型数据,
  • reactive定义:引用类型(对象、数组等)
  • ref也可以定义引用类型,内部会转译为reactive然后使用proxy进行代理挂到value上。
  • ref和reactive本质我们可以简单的理解为ref是对reactive的二次包装。

# 基本使用

<script setup>
import { reactive } from 'vue'

const state = reactive({ count: 0 })

import { ref } from 'vue'

const count = ref(0)
1
2
3
4
5
6
7
8

# ts中使用

import { ref } from 'vue'
import type { Ref } from 'vue'

const year: Ref<string | number> = ref('2020')

year.value = 2020 // 成功!


import { reactive } from 'vue'

interface Book {
  title: string
  year?: number
}

const book: Book = reactive({ title: 'Vue 3 指引' })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 原理Proxy

用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)

# DOM更新nextTick

  import { nextTick } from 'vue'
  nextTick(() => {
    // 访问更新后的 DOM
  })
1
2
3
4

# 计算属性

import { reactive, computed } from 'vue'

const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { ref, computed } from 'vue'

const count = ref(0)

const double = computed<number>(() => {
  // 若返回值不是 number 类型则会报错
})

const result = double.value.split('')
1
2
3
4
5
6
7
8
9

# 生命周期函数

import { onMounted } from 'vue'

onMounted(() => {
  console.log(`the component is now mounted.`)
})
1
2
3
4
5

# watch

  • 使用
import { ref, watch } from 'vue'
const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')

// 可以直接侦听一个 ref
watch(question, (newQuestion, oldQuestion) => {

})
1
2
3
4
5
6
7
8
  • 监测多个数据源
const x = ref(0)
const y = ref(0)

// 单个 ref
watch(x, (newX) => {
  console.log(`x is ${newX}`)
})

// getter 函数
watch(
  () => x.value + y.value,
  (sum) => {
    console.log(`sum of x + y is: ${sum}`)
  }
)

// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
  console.log(`x is ${newX} and y is ${newY}`)
})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  • 深度对象某个值
// 提供一个 getter 函数
watch(
  () => obj.count,
  (count) => {
    console.log(`count is: ${count}`)
  }
)
1
2
3
4
5
6
7
  • 深度监测
watch(
  () => state.someObject,
  (newValue, oldValue) => {
    // 注意:`newValue` 此处和 `oldValue` 是相等的
    // *除非* state.someObject 被整个替换了
  },
  { deep: true }
)
1
2
3
4
5
6
7
8
  • 即时监测
watch(source, (newValue, oldValue) => {
  // 立即执行,且当 `source` 改变时再次执行
}, { immediate: true })
1
2
3
  • 停止监测

侦听器必须用同步语句创建:如果用异步回调创建一个侦听器,那么它不会绑定到当前组件上,你必须手动停止它

import { watchEffect } from 'vue'

// 它会自动停止
watchEffect(() => {})

// ...这个则不会!
setTimeout(() => {
  watchEffect(() => {})
}, 100)

const unwatch = watchEffect(() => {})

// ...当该侦听器不再需要时
unwatch()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 组件

# 注册

import { createApp } from 'vue'

const app = createApp({})

app.component(
  // 注册的名字
  'MyComponent',
  // 组件的实现
  {
    /* ... */
  }
)
1
2
3
4
5
6
7
8
9
10
11
12
import ComponentA from './ComponentA.vue'
1

# props

  • 基本使用
import { defineProps } from 'vue'
const props = defineProps(['title'])
console.log(props.title)

defineProps({
  title: String,
  likes: Number,
  // 对象类型的默认值
  propE: {
    type: Object,
    // 对象或数组的默认值
    // 必须从一个工厂函数返回。
    // 该函数接收组件所接收到的原始 prop 作为参数。
    default(rawProps) {
      return { message: 'hello' }
    }
  },
   // 自定义类型校验函数
  propF: {
    validator(value) {
      // The value must match one of these strings
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
})

const props = defineProps({
  foo: { type: String, required: true },
  bar: Number
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  • ts中使用
const props = defineProps<{
  foo: string
  bar?: number
}>()

1
2
3
4
5
  • ts接口声明
interface Props {
  foo: string
  bar?: number
}

const props = defineProps<Props>()
1
2
3
4
5
6

# 事件监听

  • 基础使用
<button @click="$emit('enlarge-text')">Enlarge text</button>
<MyComponent @some-event="callback" />
1
2
const emit = defineEmits(['enlarge-text'])

emit('enlarge-text')
1
2
3
  • 校验
const emit = defineEmits({
  // 没有校验
  click: null,

  // 校验 submit 事件
  submit: ({ email, password }) => {
    if (email && password) {
      return true
    } else {
      console.warn('Invalid submit event payload!')
      return false
    }
  }
})

function submitForm(email, password) {
  emit('submit', { email, password })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • ts中使用
// 基于类型
const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()
1
2
3
4
5

# 双向绑定v-model

  • 基础使用
<MyComponent v-model:title="bookTitle" />
1
<script setup>
defineProps(['title'])
defineEmits(['update:title'])
</script>

<template>
  <input
    type="text"
    :value="title"
    @input="$emit('update:title', $event.target.value)"
  />
</template>
1
2
3
4
5
6
7
8
9
10
11
12
  • 自定义修饰符
<script setup>
const props = defineProps({
  modelValue: String,
  modelModifiers: { default: () => ({}) }
})

const emit = defineEmits(['update:modelValue'])

function emitValue(e) {
  let value = e.target.value
  if (props.modelModifiers.capitalize) {
    value = value.charAt(0).toUpperCase() + value.slice(1)
  }
  emit('update:modelValue', value)
}
</script>

<template>
  <input type="text" :value="modelValue" @input="emitValue" />
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 自定义指令

// 在模板中启用 v-focus
const vFocus = {
  mounted: (el) => el.focus()
}

app.directive('color', (el, binding) => {
  // 这会在 `mounted` 和 `updated` 时都调用
  el.style.color = binding.value
})

1
2
3
4
5
6
7
8
9
10
上次更新: 2024/01/18, 10:44:15
组件通信方式
从零搭建 vite+vue3+ts+pinia 框架

← 组件通信方式 从零搭建 vite+vue3+ts+pinia 框架→

最近更新
01
webpack打包替换类名命名空间
05-01
02
Vite常用配置
02-26
03
crypto前端加密
01-18
更多文章>
Theme by Vdoing | Copyright © 2022-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式