Vue核心语法(补充)

目录

computed

核心特点

[get () ------ 读取](#get () —— 读取)

[set () ------ 修改](#set () —— 修改)

watch

[watch情况一 ------ 监视ref定义的基本类型数据](#watch情况一 —— 监视ref定义的基本类型数据)

[watch情况二 ------ 监视ref定义的对象类型数据](#watch情况二 —— 监视ref定义的对象类型数据)

[watch情况三 ------ 监视reactive定义的对象类型数据](#watch情况三 —— 监视reactive定义的对象类型数据)

[watch情况四 ------ 监视ref或reactive定义的对象类型数据的某一个数据](#watch情况四 —— 监视ref或reactive定义的对象类型数据的某一个数据)

[watch情况五 ------ 监视上四种情况的多个数据](#watch情况五 —— 监视上四种情况的多个数据)

watchEffect

与watch相比

props

三种用法总结

生命周期

[Vue3 的生命周期](#Vue3 的生命周期)

自定义hook

使用流程

[自定义 Hook 命名规则](#自定义 Hook 命名规则)


对上一篇博客的语法补充

computed

作用: 根据已有数据计算出新数据

核心特点

  1. 依赖数据变,它就自动变
    • 姓 / 名一改,全名自动更新
  2. 有缓存,不重复计算
    • 数据没变时,直接用上次结果,性能高
  3. 像变量一样使用
    • 直接写 {``{ fullName }},不用加括号调用
  4. 可以只可读,也可以可读可写
python 复制代码
<template>
  <div class="person">
    姓:<input type="text" v-model="firstName" /> <br>
    名:<input type="text" v-model="lastName" /> <br>
    全名:<span>{{ fullName }}</span> <br>
    <button @click="changeFullName">全名改为:li-si</button>
  </div>
</template>

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

const firstName = ref('zhang')
const lastName = ref('san')

const fullName = computed({
  get() {
    return firstName.value + '-' + lastName.value
  },
  set(val) {
    let [f, l] = val.split('-')
    firstName.value = f || ''
    lastName.value = l || ''
  }
})

function changeFullName() {
  fullName.value = 'li-si'
}
</script>

get () ------ 读取

  • 页面显示 fullName
  • 依赖数据(firstName/lastName)变化时

触发get()并返回计算好的全名


set () ------ 修改

手动给**fullName 赋值** 时触发set(),把新值拆回去,更新原来的姓和名

原始数据

手动改动名字,跟着改变

自动改名(点击按钮)

watch

  • 作用:监视数据的变化
  • 特点: Vue3 中的 watch 只能监视以下四种数据
  1. ref 定义的数据
  2. reactive 定义的数据
  3. 函数返回一个值**(** getter 函数)
  4. 一个包含上述内容的数组

watch情况一 ------ 监视ref定义的基本类型数据

语法格式:watch(要监听的数据,回调函数)

直接写数据名,监视value值变化

回调函数:

  • newValue:修改后的新值
  • oldValue:修改前的旧值
python 复制代码
let sum = ref(0)
// 方法
function changeSum(){
    sum.value += 1
}


// 监视情况一
const stopWatch = watch(sum,(newValue,oldValue)=>{
    console.log('sum变化了',newValue,oldValue)
    if(newValue >= 10){
        stopWatch()
    }
})
  • watch 调用后返回一个停止函数 ,接收存到变量stopWatch; 调用stopWatch()即可取消监听
  • 数值≥10 之后,再点击按钮不再触发 watch 打印

watch情况二 ------ 监视ref定义的对象类型数据

  • 直接写数据名,监视的是对象的地址值

  • 若想监视对象内部的数据,要手动开启深度监视
    需要注意的是

  • 修改的是 ref 定义的对象中的属性, newValue 和 oldValue 都是新值,因为它们是同一个对象

  • 修改整个 ref 定义的对象, newValue 是新值, oldValue 是旧值,因为不是同一个对象了

python 复制代码
const person = ref({
  name: '张三',
  age: 18
})

// 修改姓名
function changeName() {
  person.value.name += '~'
}
// 修改年龄
function changeAge() {
  person.value.age += 1
}
// 直接替换整个对象
function changePerson() {
  person.value = { name: '李四', age: 90 }
}


// 监视情况二
// ref存对象默认只监听地址;改内部属性需开启deep深度监听

watch(person, (newVal, oldVal) => {
  console.log('person变化了', newVal, oldVal)
}, { deep: true })
  • ref包裹对象,直接改属性 (name/age) 不会触发 watch,deep:true开启深度监听
  • 直接赋值**person.value = {}**替换对象地址,不加 deep 也能触发监听

watch情况三 ------ 监视reactive定义的对象类型数据

默认开启了深度监视

python 复制代码
// reactive对象,watch默认自带深度监听
const person = reactive({
  name: '张三',
  age: 18
})

// 多层嵌套对象
const obj = reactive({
  a: {
    b: {
      c: 666
    }
  }
})



// 方法
function changeName() {
  person.name += '~'
}
function changeAge() {
  person.age += 1
}
function changePerson() {
  Object.assign(person, { name: '李四', age: 80 })
}
function test() {
  obj.a.b.c = 888
}



// 监视情况三
// 直接监听reactive对象:默认开启深度监听,修改任意层级属性均可触发watch,无需deep:true

watch(person, (newVal, oldVal) => {
  console.log('person变化了', newVal, oldVal)
})

watch(obj, (newVal, oldVal) => {
  console.log('Obj变化了', newVal, oldVal)
})

监听对象单个属性规则:

  1. 属性为基础类型:监听源必须写成()=>person.name函数形式
  2. 属性为子对象:推荐统一写成函数;想监听子对象内部再加**deep:true**
  3. 整对象直接监听:reactive默认深度,ref对象需手动**deep:true**

watch情况四 ------ 监视ref或reactive定义的对象类型数据的某一个数据

注意点如下:

  1. 若该属性值不是****对象类型,需要写成函数形式。
  2. 若该属性值是依然****是对象类型,需要关注对象内部(可直接编,也可写成函数,建议写成函数 ),需要手动开启深度监视
python 复制代码
// 响应式对象(包含嵌套对象 car)
const person = reactive({
  name: '张三',
  age: 18,
  car: {
    c1: '奔驰',
    c2: '宝马'
  }
})


function changeName() {
  person.name += '~'
}
function changeAge() {
  person.age += 1
}
function changeC1() {
  person.car.c1 = '奥迪'
}
function changeC2() {
  person.car.c2 = '大众'
}
function changeCar() {
  person.car = { c1: '雅迪', c2: '爱玛' }
}

// 监视情况四
// 监听对象内的基础类型属性:必须写成函数
// watch(() => person.name, (newVal, oldVal) => {})

// 监听对象内的对象类型属性:推荐写成函数 + deep:true
watch(() => person.car, (newVal, oldVal) => {
  console.log('car 变化了', newVal, oldVal)
}, { deep: true })

监听对象里的普通属性 → 必须写成函数:

javascript 复制代码
watch(() => person.name, () => {})

监听对象里的子对象

  • 必须写成函数
  • 想监听内部属性变化(c1/c2)→ 必须加 deep: true

watch情况五 ------ 监视上四种情况的多个数据

python 复制代码
const person = reactive({
  name: '张三',
  age: 18,
  car: {
    c1: '奔驰',
    c2: '宝马'
  }
})

// 修改方法
function changeName() {
  person.name += '~'
}
function changeAge() {
  person.age += 1
}
function changeC1() {
  person.car.c1 = '奥迪'
}
function changeC2() {
  person.car.c2 = '大众'
}
function changeCar() {
  person.car = { c1: '雅迪', c2: '爱玛' }
}

// 情况五:同时监听多个数据
watch([() => person.name, person.car], (newVal, oldVal) => {
  console.log('数据变化了', newVal, oldVal)
}, { deep: true })

同时监听 namecar,任意一个变化都会触发监听

watchEffect

立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数

与watch相比

  1. 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
  2. watch :要明确指出监视的数据
    3. watchEffect :不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属
    性)
python 复制代码
const temp = ref(0)
const height = ref(0)


function changePrice() {
  temp.value += 10
}
function changeSum() {
  height.value += 1
}


// 监视情况五
// watch:需明确指定监听的数据
watch([temp, height], (value) => {
  const [newTemp, newHeight] = value
  if (newTemp >= 50 || newHeight >= 20) {
    console.log('联系服务器')
  }
})

// watchEffect:自动追踪依赖,无需指定监听数据
const stopWatch = watchEffect(() => {
  if (temp.value >= 50 || height.value >= 20) {
    console.log('联系服务器')
  }
  
  // 满足条件后停止监听
  if (temp.value === 100 || height.value === 50) {
    stopWatch()
  }
})

总的来说

  • watch:手动指定监听谁
  • watchEffect:自动识别用到的响应式数据,代码更简洁

props

props = 父组件给子组件传数据的通道

  • 父组件:把数据传出去
  • 子组件:用 props 接收

父组件

python 复制代码
<template>
  <!-- 向子组件传参 -->
  <Child :name="name" :age="age" :car="car" />
</template>

<script setup lang="ts">
import Child from './Child.vue'
const name = '张三'
const age = 18
const car = { c1: '奔驰', c2: '宝马' }
</script>

子组件

python 复制代码
<template>
  <div>
    {{ props.name }}|{{ props.age }}|{{ props.car.c1 }}
  </div>
</template>

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

// =====写法1:数组写法
// const props = defineProps(['name','age','car'])

// =====写法2:对象写法
/* const props = defineProps({
  name: { type: String, required: true },
  age: { type: Number, default: 1 },
  car: { type: Object, default: () => ({c1:'雅迪',c2:'爱玛'}) }
}) */

// =====写法3:TS泛型+withDefaults(这个是vue常用)
interface User {
  name: string
  age?: number
  car?: { c1: string; c2: string }
}
const props = withDefaults(defineProps<User>(), {
  age: 1,
  car: () => ({ c1: '雅迪', c2: '爱玛' })
})
</script>

三种用法总结

  1. 数组:只接收参数,不能限制类型、默认值,临时快速开发用
  2. 对象 :JS 项目标配,可配置type/required/default,对象默认值必须函数返回
  3. withDefaults + 泛型:TS 项目,精准类型约束 + 默认值,企业最常用

生命周期

Vue 组件实例在创建时要经历一系列的初始化步骤 ,在此之前,调用特定的函数 ,让开发者有机会在特定阶段运行自己的代码,这些特定的函数就是生命周期 钩子

  • 生命周期整体分为四个阶段,分别是:创建、挂载、更新、销毁 ,每个阶段都有两个钩子,一前一后

Vue3 的生命周期

  • 创建阶段: setup
  • 挂载阶段: onBeforeMount 、 onMounted
  • 更新阶段: onBeforeUpdate 、 onUpdated
  • 卸载阶段: onBeforeUnmount 、 onUnmounted
  • 常用的钩子: onMounted (挂载完毕)、 onUpdated (更新完毕)、 onBeforeUnmount (卸载之前)

钩子示例代码

python 复制代码
<template>
  <div class="person">
    <h2>当前求和为:{{ sum }}</h2>
    <button @click="changeSum">点我 sum+1</button>
  </div>
</template>

<script setup lang="ts">
import {
  ref,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted
} from 'vue'

// 响应式数据
const sum = ref(0)

// 方法
function changeSum() {
  sum.value += 1
}

console.log('setup')

// 生命周期钩子
onBeforeMount(() => {
  console.log('挂载之前')
})
onMounted(() => {
  console.log('挂载完毕')
})
onBeforeUpdate(() => {
  console.log('更新之前')
})
onUpdated(() => {
  console.log('更新完毕')
})
onBeforeUnmount(() => {
  console.log('卸载之前')
})
onUnmounted(() => {
  console.log('卸载完毕')
})
</script>

自定义hook

一个普通函数,里面可以用 Vue3 的响应式、生命周期、watch 等所有 API
优势:

  • 复用代码
  • 让组件更干净
  • 逻辑单独维护

使用流程

首先新建一个hook的ts文件

TypeScript 复制代码
// 自定义 Hook:useSum
import { ref } from 'vue'

export default function useSum() {
  // 数据
  const sum = ref(0)

  // 方法
  const addSum = () => {
    sum.value++
  }

  // 把数据和方法 return 出去,给组件用
  return {
    sum,
    addSum
  }
}

然后在组件里使用

TypeScript 复制代码
<template>
  <div>
    <h2>求和:{{ sum }}</h2>
    <button @click="addSum">+1</button>
  </div>
</template>

<script setup lang="ts">
// 引入自定义 hook
import useSum from '@/hooks/useSum'

// 直接使用
const { sum, addSum } = useSum()
</script>

自定义 Hook 命名规则

必须以 use 开头

  • useSum
  • useMouse
  • useRequest
  • useScroll

下一篇介绍一下vue的两个生态以及组件之间的连接方式

相关推荐
问心无愧051317 小时前
ctf show web入门160 161
前端·笔记
李小白6617 小时前
第四天-WEB服务器基本原理,IIS服务
运维·服务器·前端
humcomm18 小时前
AI编程时代新前端职位
前端·ai编程
好家伙VCC18 小时前
Web Components主题热切换方案揭秘
java·前端
甲维斯18 小时前
Kimi版超级玛丽效果“惊人”,配额不足5厘米!
前端·人工智能
hboot19 小时前
AI工程师第一课 - Python
前端·后端·python
凉菜凉凉19 小时前
AI时代,被抛弃的前端
前端·ai
console.log('npc')19 小时前
AI前端工程与生成式UI学习路线
前端·人工智能·ui
huangdong_19 小时前
淘宝商品SKU图自动分类技术深度解析:从DOM解析到智能归档
开发语言·javascript·ecmascript
梦曦i19 小时前
uni-router v1.1.1发布:守卫超时保护+路由监听
前端·uni-app