036_Vue 3 核心知识体系第一部分:基础概念和响应式系统

内容分享1天前发布
1 0 0

1. Vue 3 核心概念

1.1 Vue 是什么

Vue 是一个渐进式 JavaScript 框架,用于构建用户界面。特点:

  • 渐进式:可以逐步采用,从简单到复杂
  • 声明式渲染:使用模板语法声明式地描述界面
  • 组件化:构建可复用的组件
  • 响应式:数据变化自动更新视图

1.2 Vue 3 新特性

javascript

// 1. Composition API(组合式API)
// 2. Teleport(传送门)
// 3. Fragments(片段)
// 4. Emits Option(自定义事件选项)
// 5. 更好的 TypeScript 支持
// 6. 更小的体积(Tree-shaking 优化)
// 7. 更快的性能(Proxy 取代 defineProperty)

2. 响应式系统

2.1 响应式基础

vue

<script setup>
import { ref, reactive, toRefs } from 'vue'

// ref: 用于基本类型
const count = ref(0) // 创建响应式数据
console.log(count.value) // 访问值
count.value++ // 修改值

// reactive: 用于对象
const state = reactive({
  name: 'Vue 3',
  version: '3.3'
})
console.log(state.name) // 直接访问
state.version = '3.4' // 直接修改

// toRefs: 将响应式对象转换为 ref 集合
const { name, version } = toRefs(state)
</script>

2.2 ref 详解

javascript

// ref 创建响应式引用
const count = ref(0)

// ref 也可以用于对象
const objRef = ref({
  name: 'test',
  value: 123
})

// 模板中会自动解包 .value

2.3 reactive 详解

javascript

// reactive 创建响应式对象
const state = reactive({
  name: 'John',
  age: 30,
  address: {
    city: 'Beijing',
    street: 'Main St'
  }
})

// 嵌套对象也是响应式的
state.address.city = 'Shanghai' // 触发响应

// 注意事项:
// 1. 只能用于对象类型
// 2. 替换整个对象会失去响应性
// 3. 解构会失去响应性

2.4 响应式工具函数

javascript

import {
  isRef,
  unref,
  toRef,
  toValue,
  shallowRef,
  triggerRef,
  markRaw,
  shallowReactive,
  readonly
} from 'vue'

// isRef: 检查是否为 ref
console.log(isRef(count)) // true

// unref: 如果是 ref 返回 value,否则返回本身
const value = unref(maybeRef)

// toRef: 为响应式对象的属性创建 ref
const nameRef = toRef(state, 'name')

// shallowRef: 浅层 ref(只跟踪 .value 变化)
const shallowObj = shallowRef({ a: 1 })
shallowObj.value.a = 2 // 不会触发响应!

// readonly: 创建只读代理
const readOnlyState = readonly(state)
readOnlyState.name = 'new' // 会报错

// markRaw: 标记对象为"原始",不会被转换为响应式
const nonReactive = markRaw({ shouldNotBeReactive: true })

3. 计算属性和侦听器

3.1 计算属性

vue

<script setup>
import { ref, computed } from 'vue'

const price = ref(100)
const quantity = ref(2)

// 计算属性(只读)
const total = computed(() => {
  return price.value * quantity.value
})

// 计算属性(可写)
const fullName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`
  },
  set(newValue) {
    const [first, last] = newValue.split(' ')
    firstName.value = first
    lastName.value = last || ''
  }
})
</script>

3.2 侦听器

vue

<script setup>
import { ref, watch, watchEffect } from 'vue'

const count = ref(0)
const state = reactive({ a: 1, b: 2 })

// watch: 监听单个或多个源
watch(count, (newVal, oldVal) => {
  console.log(`count变化: ${oldVal} -> ${newVal}`)
})

// 监听多个源
watch([count, () => state.a], ([newCount, newA], [oldCount, oldA]) => {
  console.log('多个源变化')
})

// 深度监听
watch(
  state,
  (newVal, oldVal) => {
    // 注意:newVal 和 oldVal 一样
    console.log('state 深度变化')
  },
  { deep: true }
)

// 立即执行
watch(count, callback, { immediate: true })

// watchEffect: 立即执行,自动追踪依赖
watchEffect(() => {
  console.log(`count: ${count.value}, a: ${state.a}`)
  // 自动追踪 count.value 和 state.a
})

// 停止侦听器
const stop = watchEffect(() => {})
stop() // 停止侦听
</script>

3.3 watch vs watchEffect

特性

watch

watchEffect

懒执行

✅ 默认懒执行

❌ 立即执行

依赖追踪

❌ 需要明确指定

✅ 自动追踪

新旧值

✅ 提供新旧值

❌ 不提供

适合场景

需要新旧值对比

不需要新旧值

4. 生命周期钩子

4.1 生命周期图示

text

setup() → beforeCreatecreatedonBeforeMountonMountedonBeforeUpdateonUpdatedonBeforeUnmountonUnmounted

4.2 组合式 API 钩子

vue

<script setup>
import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured,
  onActivated,
  onDeactivated,
  onRenderTracked,
  onRenderTriggered
} from 'vue'

// 组件挂载后
onMounted(() => {
  console.log('组件已挂载')
  // DOM 操作可以在这里进行
})

// 组件更新前
onBeforeUpdate(() => {
  console.log('组件即将更新')
})

// 组件销毁前
onBeforeUnmount(() => {
  console.log('组件即将销毁')
  // 清理工作
})

// 错误捕获
onErrorCaptured((err, instance, info) => {
  console.error('捕获到错误:', err)
  return false // 阻止错误继续向上传播
})

// KeepAlive 组件特有
onActivated(() => {
  console.log('组件被激活')
})

onDeactivated(() => {
  console.log('组件被停用')
})
</script>

4.3 选项式 API 钩子

javascript

export default {
  data() {
    return { count: 0 }
  },
  
  // 初始化前
  beforeCreate() {
    console.log('beforeCreate')
  },
  
  // 初始化后
  created() {
    console.log('created')
  },
  
  // 挂载前
  beforeMount() {
    console.log('beforeMount')
  },
  
  // 挂载后
  mounted() {
    console.log('mounted')
  },
  
  // 更新前
  beforeUpdate() {
    console.log('beforeUpdate')
  },
  
  // 更新后
  updated() {
    console.log('updated')
  },
  
  // 卸载前
  beforeUnmount() {
    console.log('beforeUnmount')
  },
  
  // 卸载后
  unmounted() {
    console.log('unmounted')
  },
  
  // 错误捕获
  errorCaptured(err, instance, info) {
    console.error('错误:', err)
    return false
  }
}

5. 模板语法

5.1 文本插值

vue

<template>
  <!-- 文本插值 -->
  <p>{{ message }}</p>
  
  <!-- 原始 HTML -->
  <p v-html="rawHtml"></p>
  
  <!-- 属性绑定 -->
  <div :id="dynamicId"></div>
  <button :disabled="isDisabled">按钮</button>
  
  <!-- 布尔属性 -->
  <button :disabled="isButtonDisabled">按钮</button>
  
  <!-- 动态绑定多个属性 -->
  <div v-bind="objectOfAttrs"></div>
</template>

5.2 指令

vue

<template>
  <!-- v-if / v-else-if / v-else -->
  <div v-if="type === 'A'">A</div>
  <div v-else-if="type === 'B'">B</div>
  <div v-else>C</div>
  
  <!-- v-show -->
  <div v-show="isVisible">显示/隐藏</div>
  
  <!-- v-for -->
  <li v-for="(item, index) in items" :key="item.id">
    {{ index }}: {{ item.text }}
  </li>
  
  <!-- v-for 遍历对象 -->
  <li v-for="(value, key, index) in myObject">
    {{ index }}. {{ key }}: {{ value }}
  </li>
  
  <!-- v-on 事件处理 -->
  <button @click="handleClick">点击</button>
  
  <!-- 事件修饰符 -->
  <form @submit.prevent="onSubmit">
    <input @keyup.enter="submit" />
  </form>
  
  <!-- v-model 双向绑定 -->
  <input v-model="message" />
  <textarea v-model="text"></textarea>
  <input type="checkbox" v-model="checked" />
  <select v-model="selected">
    <option value="A">A</option>
  </select>
  
  <!-- v-model 修饰符 -->
  <input v-model.lazy="msg" />  <!-- change 事件后同步 -->
  <input v-model.number="age" /> <!-- 转为数字 -->
  <input v-model.trim="name" /> <!-- 去除首尾空格 -->
</template>

5.3 动态参数

vue

<template>
  <!-- 动态属性名 -->
  <div :[attributeName]="attributeValue"></div>
  
  <!-- 动态事件名 -->
  <button @[eventName]="handler"></button>
  
  <!-- 动态插槽名 -->
  <template #[dynamicSlotName]></template>
</template>

<script setup>
const attributeName = ref('id')
const eventName = ref('click')
const dynamicSlotName = ref('header')
</script>

6. 组件基础

6.1 组件定义

vue

<!-- 选项式 API -->
<script>
export default {
  // 组件名称
  name: 'MyComponent',
  
  // 接收的 props
  props: {
    title: String,
    count: {
      type: Number,
      default: 0,
      required: true,
      validator: value => value >= 0
    }
  },
  
  // 本地状态
  data() {
    return {
      localCount: 0
    }
  },
  
  // 计算属性
  computed: {
    total() {
      return this.count + this.localCount
    }
  },
  
  // 方法
  methods: {
    increment() {
      this.localCount++
    }
  },
  
  // 生命周期
  mounted() {
    console.log('组件已挂载')
  }
}
</script>

6.2 组合式 API 组件

vue

<!-- MyComponent.vue -->
<template>
  <div>
    <h2>{{ title }}</h2>
    <p>{{ count }}</p>
    <button @click="increment">增加</button>
  </div>
</template>

<script setup>
import { ref, defineProps, defineEmits, defineExpose } from 'vue'

// 定义 props
const props = defineProps({
  title: {
    type: String,
    required: true
  },
  count: {
    type: Number,
    default: 0
  }
})

// 定义 emits
const emit = defineEmits(['update:count', 'custom-event'])

// 本地状态
const localCount = ref(0)

// 方法
const increment = () => {
  localCount.value++
  emit('update:count', props.count + 1)
  emit('custom-event', '事件触发')
}

// 暴露给父组件的方法
const publicMethod = () => {
  console.log('公共方法被调用')
}

defineExpose({
  publicMethod,
  localCount
})
</script>

6.3 组件注册

javascript

// 全局注册
import { createApp } from 'vue'
import MyComponent from './MyComponent.vue'

const app = createApp(App)
app.component('MyComponent', MyComponent)

// 局部注册
import MyComponent from './MyComponent.vue'

export default {
  components: {
    MyComponent
  }
}

6.4 使用组件

vue

<template>
  <!-- 使用组件 -->
  <MyComponent
    :title="componentTitle"
    :count="countValue"
    @update:count="handleUpdate"
    @custom-event="handleCustom"
    ref="myComponentRef"
  />
</template>

<script setup>
import { ref, onMounted } from 'vue'
import MyComponent from './MyComponent.vue'

const componentTitle = ref('组件标题')
const countValue = ref(0)
const myComponentRef = ref()

const handleUpdate = (newCount) => {
  countValue.value = newCount
}

const handleCustom = (message) => {
  console.log(message)
}

onMounted(() => {
  // 调用子组件暴露的方法
  myComponentRef.value?.publicMethod()
})
</script>

这是 Vue 3 核心知识的第一部分,涵盖了响应式系统、计算属性和侦听器、生命周期、模板语法和组件基础。

© 版权声明

相关文章

暂无评论

none
暂无评论...