# vue3 核心技术
# 1. 介绍
vue 开发者工具:
- 国内可以在 极简插件 (opens new window) 搜索并下载谷歌插件
# 2. vite 创建 vue3 工程
Vite 需要 Node.js 版本 18+ 或 20+。
示例:
npm create vite@latest
总结:
- Vite 项目中,
index.html
是项目的入口文件 - Vite 解析
<script type="module" src="src/main.ts">
参考:
# 3. 核心语法
# 3.1. OptionsAPI 与 CompositionAPI
Vue2 的 API 设计是 Options(配置)风格的
- 按配置项来拆分(组织)代码
Vue3 的 API 设计是 Composition(组合)风格的
- 按业务功能来拆分(组织)代码
# 3.2. setup
# 3.2.1. 概述
说明:
setup
是 Vue3 中一个新的配置项,组合式 API 在 setup 中才会生效
特点:
setup
函数返回的对象中的内容,可直接在模板中使用。setup
中的this
指向undefined
。setup
函数会在beforeCreate
之前调用,它是“领先”所有钩子执行的。
示例:
<template>
<div>{{ name }}</div>
<button @click="showName">showName</button>
</template>
<script>
export default {
setup() {
const name = '张三';
const showName = () => {
alert(name);
};
return {
name,
showName,
};
}
}
</script>
# 3.2.2. setup() 的返回值
setup() 的返回值:
- 对象: 对象中属性、方法可以直接在模板中使用
- 函数: 可以自定义渲染内容
示例:
export default {
setup() {
let name = '张三';
return { name };
}
}
export default {
setup() {
return () => '张三';
}
}
# 3.2.3. setup 与 Options API 的关系
说明:
- 在 Options API 中可以通过
this
读取到setup()
返回的内容 - 因为
setup()
先执行, 如果与 Options API 中暴露的属性名称冲突,则以 Options API 为准
示例:
<template>
<div>{{ message }}</div> <!-- hello -->
<div>{{ msg }}</div> <!-- hello -->
<div>{{ name }}</div> <!-- 李四 -->
</template>
<script lang="ts">
export default {
setup() {
return {
name: '张三',
message: 'hello',
}
},
data() {
return {
name: '李四',
msg: this.message,
}
}
}
</script>
# 3.2.4. setup 语法糖
说明:
- 彻底废弃选项式的写法
示例:
<template>
<div>{{ name }}</div>
<button @click="handleClick">button</button>
</template>
<script lang="ts" setup>
let name = '张三';
function handleClick() {
console.log(`hello, ${name}`);
}
</script>
# 3.2.5. vite-plugin-vue-setup-extend
说明:
- 引入此插件后,可以通过
<script name="组件的名称">
的方式设置组件的名称
安装:
npm i -D vite-plugin-vue-setup-extend
## "vite-plugin-vue-setup-extend": "^0.4.0",
配置: (vite.config.ts
)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import VitePluginVueSetupExtend from 'vite-plugin-vue-setup-extend'
export default defineConfig({
plugins: [
vue(),
VitePluginVueSetupExtend(),
],
})
使用:
<template>
<div>{{name}}</div>
</template>
<script lang="ts" setup name="MyComponent">
let name = 'zhangsan'
</script>
# 3.3. ref 创建:基本类型的响应式数据
作用:
- 定义响应式变量
语法:
let xxx = ref(初始值)
返回值:
RefImpl
的实例对象,简称ref对象
或ref
ref对象
的value
属性是响应式的
注意点:
- 在 JS 中读写
ref对象
需要带value
属性 - 在 模板 中使用
ref对象
不能带value
属性 - 对于
let name = ref('张三')
来说,name
不是响应式的,name.value
是响应式的
示例:
<template>
<div>{{age}}</div>
<button @click="handleClick">button</button>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
let age = ref(18);
function handleClick() {
age.value += 1;
}
</script>
# 3.4. reactive 创建:对象类型的响应式数据
作用:
- 定义一个 响应式对象 (基本类型不要用它,要用
ref
,否则报错)
语法:
let 响应式对象= reactive(源对象)
返回值:
- 一个
Proxy
的实例对象,简称:响应式对象
注意点:
reactive
定义的响应式数据是“深层次”的,即任意层级的属性都是响应式的
示例:
<template>
<div>{{person.age}}</div>
<button @click="handleClick">button</button>
</template>
<script lang="ts" setup>
import { reactive } from 'vue';
let person = reactive({
name: '张三',
age: 18
});
function handleClick() {
person.age += 1;
}
</script>
# 3.5. ref 创建:对象类型的响应式数据
说明:
ref()
接收的是数据可以是 基本类型、对象类型ref()
接收对象类型数据时,内部实际调用了reactive()
ref()
接收对象类型数据时,也需要使用.value
来获取代理对象
示例:
<template>
<div>{{person.age}}</div>
<button @click="handleClick">button</button>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
let person = ref({
name: '张三',
age: 18
});
function handleClick() {
person.value.age += 1;
}
</script>
# 3.6. ref 对比 reactive
用法:
ref
用来定义:基本类型数据、对象类型数据reactive
用来定义:对象类型数据
区别:
ref
创建的变量必须使用.value
reactive
创建的变量,重新赋值(整个对象)会失去响应式
原则:
- 若需要一个基本类型的响应式数据,必须使用
ref
。 - 若需要一个响应式对象,层级不深,
ref
、reactive
都可以。 - 若需要一个响应式对象,且层级较深,推荐使用
reactive
。
示例:
<template>
<div>{{person}}</div>
<button @click="handleClick">button</button>
</template>
<script lang="ts" setup>
import { reactive } from 'vue';
let person = reactive({
name: '张三',
age: 18
});
function handleClick() {
// 如果变量的值 是 reactive 定义的响应式数据,则只能修改其属性,不能重新赋值
// ref 则没有这个问题
Object.assign(person, { name: '李四', age: 20 })
}
</script>
# 3.7. toRefs 与 toRef
说明:
- 将响应式对象中的属性定义为 ref 对象,ref 对象的值变化 时 响应式属性的值也跟着变化
toRef
针对单个属性toRefs
针对所有属性
示例:
<template>
<div>{{person}}</div>
<div>name: {{ name }}</div>
<div>age: {{ age }}</div>
<div>gender: {{ gender }}</div>
<button @click="changeName">changeName</button>
<button @click="changeAge">changeAge</button>
<button @click="changeGender">changeGender</button>
</template>
<script lang="ts" setup>
import { reactive, toRef, toRefs } from 'vue';
let person = reactive({
name: '张三',
age: 18,
gender: '男',
});
// 直接解构响应式对象的属性,name 不是响应式的
let { name } = person;
// 将 响应式对象 中的 某个 属性定义为 ref 对象
let age = toRef(person, 'age');
// 将 响应式对象 中的 所有 属性定义为 ref 对象
let { gender } = toRefs(person);
// 执行后,不会触发模板的重新渲染
function changeName() {
name += '~';
}
function changeAge() {
age.value += 1;
}
function changeGender() {
gender.value += '!';
}
</script>
# 3.8. computed
说明:
- 和
Vue2
中的computed
作用一致
示例:
<template>
<div>姓: <input type="text" v-model="firstName"></div>
<div>名: <input type="text" v-model="lastName"></div>
<div>姓名1: {{ fullName1 }}</div>
<div>姓名2: {{ fullName2 }}</div>
<div><button @click="changeFullName2">changeFullName2</button></div>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
const firstName = ref('张');
const lastName = ref('三');
// 只读
const fullName1 = computed(() => {
return firstName.value + lastName.value;
});
// 可读可写
const fullName2 = computed({
get() {
return firstName.value + lastName.value;
},
set(val) {
firstName.value = val.slice(0, 1);
lastName.value = val.slice(1);
}
});
function changeFullName2() {
fullName2.value = '娃哈哈';
}
</script>
# 3.9. watch
作用:
- 监视数据的变化
- 和
Vue2
中的watch
作用一致
Vue3
中的 watch
只能监视以下 四种数据:
ref
定义的数据。reactive
定义的数据。- 函数返回一个值(
getter
函数)。 - 一个包含上述内容的数组。
# 3.9.1. 情况一
说明:
- 监视
ref
定义的【基本类型】数据 - 直接写数据名即可,监视的是其
value
值的改变。
示例:
<template>
<div>sum: {{ sum }}</div>
<div><button @click="changeNum">changeNum</button></div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
const sum = ref(0);
const stopWatchSum = watch(sum, (newVal, oldVal) => {
console.log(`newVal=${newVal}, oldVal=${oldVal}`);
if (newVal > 3) {
stopWatchSum();
console.log('取消监视');
}
});
function changeNum() {
sum.value += 1;
}
</script>
# 3.9.2. 情况二
说明:
- 监视
ref
定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。
注意:
- 若修改的是
ref
定义的对象中的属性,newValue
和oldValue
都是新值,因为它们是同一个对象。 - 若修改整个
ref
定义的对象,newValue
是新值,oldValue
是旧值,因为不是同一个对象了。
示例:
<template>
<div>{{ person }}</div>
<button @click="changeName">changeName</button>
<button @click="changePerson">changePerson</button>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
const person = ref({ name: '张三', age: 18 });
function changeName() {
person.value.name += '~';
}
function changePerson() {
person.value = { name: '李四', age: 20 };
}
watch(
person,
// 属性改变后,新旧值是同一个值,即 person 的对象
// person 引用改变后,新旧值不一样
(newVal, oldVal) => {
console.log('watch', newVal, oldVal );
},
{
// 如果为 false,则对象的数据变化不会触发 watch
deep: true,
// 初始化时,数据没变化也会执行一次
immediate: true,
}
);
</script>
# 3.9.3. 情况三
说明:
- 监视
reactive
定义的【对象类型】数据,且默认开启了深度监视(且无法关闭)
示例:
<template>
<div>{{ person }}</div>
<button @click="changeName">changeName</button>
<button @click="changePerson">changePerson</button>
</template>
<script lang="ts" setup>
import { reactive, watch } from 'vue';
const person = reactive({ name: '张三', age: 18 });
function changeName() {
person.name += '~';
}
function changePerson() {
Object.assign(person, { name: '李四', age: 20 });
}
watch(person, (newVal, oldVal) => {
console.log('watch', newVal, oldVal );
});
</script>
# 3.9.4. 情况四
说明:
- 监视
ref
或reactive
定义的【对象类型】数据中的某个属性
注意:
- 监视的属性是基本类型,只能写函数式
- 监视的属性是对象类型,建议写函数式
- 对象的引用变化时,新旧值不一样
- 对象的属性变化时,新旧值为同一个
示例:
<template>
<div>{{ person }}</div>
<button @click="changeName">changeName</button>
<button @click="changeCarBrand">changeCarBrand</button>
<button @click="changeCar">changeCar</button>
</template>
<script lang="ts" setup>
import { reactive, watch } from 'vue';
const person = reactive({
name: '张三',
age: 18,
car: { brand: '比亚迪', color: '白色' }
});
function changeName() {
person.name += '~';
}
function changeCarBrand() {
person.car.brand = '奔驰'
}
function changeCar() {
person.car = { brand: '宝马', color: '红色' }
}
// 监视基本类型的属性
watch(() => person.name, (newVal, oldVal) => {
console.log('person.name', newVal, oldVal );
});
// 监视对象的类型的属性: 默认监视 整个对象(对象的引用),可以设置深度监视
watch(() => person.car, (newVal, oldVal) => {
console.log('person.name 函数式', newVal, oldVal );
}, { deep: true })
// 监视对象的类型的属性: 只能监视到 对象的属性变化
watch(person.car, (newVal, oldVal) => {
console.log('person.name 直接写', newVal, oldVal );
})
</script>
# 3.9.5. 情况五
说明:
- 监视上述的多个数据
示例:
watch(
[
() => person.name, // 基本类型
() => person.car // 对象类型,深度监视需要开启 deep
],
(newVal, oldVal) => {
// newVal: [ name的新值,car的新值 ]
// oldVal: [ name的旧值,car的旧值 ]
console.log(newVal, oldVal);
},
{ deep: true }
)
# 3.10. watchEffect
说明:
- 官网:立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数。
- 类比 Vue2 中的计算属性
watch
对比watchEffect
:
- 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
watch
:要明确指出监视的数据watchEffect
:不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)
示例:
<template>
<div>({{ x }}, {{ y }})</div>
<button @click="changeX">changeX</button>
<button @click="changeY">changeY</button>
</template>
<script lang="ts" setup>
import { ref, watchEffect } from 'vue';
const x = ref(0);
const y = ref(0);
function changeX() {
x.value += 1;
}
function changeY() {
y.value += 1;
}
const stopWatch = watchEffect(() => {
if (x.value >= 3 || y.value >= 4) {
console.log('send request');
stopWatch();
}
})
</script>
上一篇: 下一篇:
本章目录