001.教程简介
1.采用方式ts+组合式API+setup语法糖
2.核心内容:ref、reactive、computed、watch、生命周期…
3.常用内容:hooks、自定义ref、路由、pinia、mitt…
4.面试:组件通信、响应式相关API…
002.Vue3
2020.9.18发布3.0(性能好、速度快、打包小)
003.创建Vue3工程
1.基于webpack vue-cli创建
vue --version
npm install -g @vue/cli
Vue create vue_test
2.基于vite创建
优点:轻量快速、对ts、jsx、css开箱即用不用配置
创建:(1)npm create vue@latest (2)npm i
*注意:安装node
项目名称:不能出现中文和特殊字符,最好纯小写英文字母+数字+下划线
文件路径.vscode==>extensions.json配置着插件[eg:]
{ “recommendations”: [“Vue.volar”] }
env.d.ts 声明各种类型文件让ts认识.jpg、.txt等文件
index.html 入口文件
vite.config.ts配置插件配置代理
3.插件名称:TypeScript Vue Plugin (Volar) 极简插件
004编写App组件
1.Vue3支持多个根标签
2.Vue3不支持this
3.setup函数比beforeCreate还要早
4.setup语法糖写法
<script setup lang='ts'></script>
5.重命名组件名称
安装插件
npm i vite-plugin-vue-setup-extend -D vite config.ts
配置插件
1)import VueSetupExtend from “vite-plugin-vue-setup-extend”;
2)追加调用VueSetupExtend( )
3)script标签中添加name
005 ref创建基本类型响应式数据
ref创建:基本类型的响应式数据
作用:定义响应式变量。
语法:let xxx= ref(初始值)
返回值:一个RefImpl的实例对象,简称ref对象或ref,ref对象的value属性是响应式的。
注意点:
js中操作数据需要:xxx.value,但模版中不需要.value,直接使用即可
对于let name = ref(‘张三’)来说,name 不是响应式的,name.value是响应式的
006 reactive创建对象类型响应式数据
reactive只能定义创建对象类型的响应式数据
简单对象、数组对象、
注意点:可以深层次对象进行响应式
007 ref对比reactive
ref ======>基本 对象
reactive ======>对象
区别:
1.ref创建的变量必须使用.value【使用volar插件可以自动添加value,设置中Volar勾选Auto Insert:Dot Value】
2.reactive重新分配一个新的对象,会失去响应式,可以使用Object.assign去整体替换
使用原则:
1.若需要一个基本类型的响应式数据,必须使用ref
2.若需要一个响应式对象,层级不深,ref、reactive都可以
3.若需要一个响应式对象,且层级较深,推荐使用reactive
008 toRefs与toRef
toRefs,toRef将解构数据进行响应式
let person = reactive({name: "zhangsan",age: 18,className: "3年2班",favarate: "爱踢足球",family: {mother: "大美丽",father: "大英俊"}
})let { name, age, className, favarate, family } = toRefs(person);
const {mother,father} = toRefs(family.value)
let nl = toRef(person,'age')
009 computed计算属性
<template><div>姓<input v-model="xing"/><br/>名<input v-model="ming"/><br/>姓名:<span>{{xingMing}}</span><button @click="changFullName">修改全名</button></div>
</template>
<script setup lang='ts'>
import { ref, reactive, toRefs, computed } from 'vue'
let xing = ref("")
let ming = ref("")
// 这么定义的xingming不可修改
let xingMing = computed({get(){return xing.value+ming.value},set(val){let [val1,val2] = val.split("-");xing.value = val1;ming.value = val2;}
})
function changFullName(){xingMing.value = "张-三"
}
</script>
010 computed计算属性
特点:vue3中的watch只能监视以下4种数据:
1.ref定义的数据
2.reactive定义的数据
3.函数返回一个值(getter函数)
4.一个包含上述内容的数组
五种情况
1.监视ref定义的【基本类型】数据,直接写数据名即可,监视的是其value值的改变
写法:函数返回的是一个停止监听的函数
watch(谁,回调函数(新的值,旧的值)=>{})
代码示例<div class="person">·<h2>情况一:监视ref定义的基本类型</h2>当前求和为{{ sum }}<button @click="changeSum">点我sum+1</button></div>
<script>// 监视,情况一:监视ref定义的基本类型
// 数据
let sum = ref(0);
// 方法
function changeSum() {sum.value++;
}
// 监视,情况一:监视ref定义的基本类型 两个参数【监视对象,回调函数】
// *注意sum不用写value
const stopwatch = watch(sum, (newVal, oldVal) => {console.log("求和数据发生了变化", newVal, oldVal);if (newVal > 10) stopwatch()
})
console.log('监视方法返回值', stopwatch);
</script >
2.监视ref定义的【对象类型】数据,监视的是对象的地址值,若想监视对象内容属性的变化,需要手动开启深度模式;
*immediate:true 立即修改,开发时避免参数中写"新的值"、“旧的值”,直接写value
写法:
watch(谁,回调函数(新的值,旧的值)=>{},{deep:true})
代码示例:
// 监视,情况二:监视ref定义的对象类型
let person = ref({name: "张三",age: 18
})
function changeName() {person.value.name += '@'
}
function changeAge() {person.value.age++;
}
function changePerson() {person.value = {name: "zhangsan",age: 0}
}
//监视的是对象的地址值,若想 监视对象内部属性的值需要开启深度监视
watch(person, (newVal, oldVal) => {console.log("person变化", newVal, oldVal);
}, { deep: true, immediate: true })
3.监视reactive定义的对象类型,数据,且默认开启了深度监视,不可以关闭
<div class="person"><h2>情况三:监视reactive定义的对象类型</h2>姓名{{ reactivePerson.name }}<br />年龄{{ reactivePerson.age }}<button @click="reactivechangeName">reActive修改名字</button><button @click="reactivechangeAge">reActive修改年龄</button><button @click="reactivechangePerson">reActive修改整个人</button><h2>测试数据{{ testData.a.b.c.d }}</h2><button @click="changeTest">修改测试数据</button></div>
// 监视,情况三:监视reactive定义的对象类型
let reactivePerson = reactive({name: "张三",age: 18
})
let testData = reactive({a: {b: {c: {d: "测试数据"}}}
})
function reactivechangeName() {reactivePerson.name += '@'
}
function reactivechangeAge() {reactivePerson.age++;
}
function reactivechangePerson() {Object.assign(reactivePerson, {name: "zhangsan",age: 0})
}
// 监视reactive定义的对象类型,数据,且默认开启了深度监视,不可以关闭
watch(reactivePerson, (newVal, oldVal) => {console.log("reactivePerson", newVal, oldVal);
})
function changeTest() {testData.a.b.c.d = "修改了test数据"
}
watch(testData, () => {console.log("监听到了修改的测试数据");
})
4.监视ref或reactive定义的【对象类型】数据中的某个属性,注意点如下:
(1).若该属性值不是【对象类型】(基本类型),需要写成函数形式
(2).若该属性值是依然是【对象类型】,可直接编,也可写成函数,注意:直接写整体改变不能监听到,建议写成:函数式需要深度监听
结论:监视的要是对象里的属性,最好是函数形式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视
<div class="person"><h2>情况四对象属性</h2>姓名{{ qingkuang4.name }}<br />年龄{{ qingkuang4.age }}<br />汽车{{ qingkuang4.car.c1 }}、{{ qingkuang4.car.c2 }}<br /><button @click="qingkuang4changename">reActive修改名字</button><br /><button @click="qingkuang4changeage">reActive修改年龄</button><br /><button @click="qingkuang4changeonecar">修改第一台车</button><br /><button @click="qingkuang4changetwocar">修改第二台车</button><br /><button @click="qingkuang4changeallcar">修改整个车</button></div>
// 监视,情况四:监视reactive定义的对象类型属性
// 数据
let qingkuang4 = reactive({name: "张三",age: 18,car: {c1: '奔驰',c2: '宝马'}
})
function qingkuang4changename() {qingkuang4.name += "#";
}
function qingkuang4changeage() {qingkuang4.age++;
}
function qingkuang4changeonecar() {qingkuang4.car.c1 = "奥迪"
}
function qingkuang4changetwocar() {qingkuang4.car.c2 = "大众"
}
function qingkuang4changeallcar() {qingkuang4.car = {c1: '雅迪',c2: '艾玛'}
}
// 若该属性值不是【对象类型】(基本类型),需要写成函数形式
watch(() => qingkuang4.name, (newVal,oldVal) => {console.log("改变了对象属性name",newVal,oldVal);
})
// 若该属性值是依然是【对象类型】,可直接编,也可写成函数
// 注意:直接写整体改变不能监听到,建议写成:函数式需要深度监听
// watch(qingkuang4.car,()=>{
// console.log("改变了对象属性car直接写");
// })
watch(() => qingkuang4.car, () => {console.log("改变了对象属性car函数式");
}, { deep: true })
5.监视上述的多个数据
watch([xxx,xxx,xxxx],(newVal,oldVal)=>{console.log("改变了######",newVal,oldVal);
},{deep:true})
xxx是直接写还是函数取决于xxx的类型
<div class="person"><h2>情况五:监视上述多个数据数组</h2>姓名{{ zonghe.name }}<br />年龄{{ zonghe.age }}<br />汽车{{ zonghe.car.c1 }}、{{ zonghe.car.c2 }}<br /><button @click="zonghechangename">reActive修改名字</button><br /><button @click="zonghechangeage">reActive修改年龄</button><br /><button @click="zonghechangeonecar">修改第一台车</button><br /><button @click="zonghechangetwocar">修改第二台车</button><br /><button @click="zonghechangeallcar">修改整个车</button></div>
let zonghe = reactive({name: "张三",age: 18,car: {c1: '奔驰',c2: '宝马'}
})
function zonghechangename() {zonghe.name += "#";
}
function zonghechangeage() {zonghe.age++;
}
function zonghechangeonecar() {zonghe.car.c1 = "奥迪"
}
function zonghechangetwocar() {zonghe.car.c2 = "大众"
}
function zonghechangeallcar() {zonghe.car = {c1: '雅迪',c2: '艾玛'}
}
watch([() => zonghe.name, () => zonghe.car.c1], (newVal, oldVal) => {console.log("改变了######", newVal, oldVal);
},{deep:true})
011 watchEffect
立即运行一个函数,同时响应式地追踪依赖,并在依赖更改时重新执行该函数
watch对比watchEffect
1.都能监听响应式数据变化,不同的是监听数据变化的方式不同
2.watch要明确指出监视的数据
3.watchEffect:不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些数据)
<template><div>温度:{{ temp }}<br />湿度:{{ shidu }}<br /><button @click="changeVal1">改变温度</button><button @click="changeVal2">改变湿度</button></div>
</template>
<script setup lang='ts'>
import { ref, reactive, toRefs, watchEffect } from "vue";
let temp = ref(0);
let shidu = ref(0);
function changeVal1() {temp.value++;
}
function changeVal2() {shidu.value++;
}
watchEffect(() => {if (temp.value > 10) {console.log("温度过高了");}if (shidu.value > 10) {console.log("湿度过高了");}
})
</script>
012 标签的ref属性
挂在普通标签输入当前元素
<template><div><h3 ref="h3tag">我是h3标签</h3><button @click="outputContent">输出</button></div>
</template>
<script setup lang='ts'>
import { ref, reactive, toRefs } from 'vue'
let h3tag = ref();
function outputContent(){console.log(h3tag.value);//<h3>我是h3标签</h3>
}
</script>
挂在组件上输入组件实例,需要在子组件上导出父组件才可看见
Parent.vue
<template><Child ref="haizi"/><button @click="outputContent">输入</button>
</template>
<script setup lang='ts'>
import {ref} from 'vue'
import Child from './Child.vue'
let haizi = ref();
function outputContent(){let refTemp = haizi.value;console.log(refTemp.b);
}
</script>
Child.vue
<template><div>子组件</div>
</template>
<script setup lang='ts'>
import { ref} from 'vue'
let a = ref(0)
let b = ref(1)
let c = ref(2)
defineExpose({a,b,c})
</script>
013TS自定义类型
// 定义一个接口用于限制Person的具体属性
export interface PersonInter {id: string;name: string;age: number;
}
// 自定义类型写法1
// export type Personns = Array<PersonInter>;
// 自定义类型写法2
export type Personns = PersonInter[];
<script setup lang="ts" name="person">
import { type PersonInter,type Personns } from '@/types'
let person: PersonInter = {id: "xxxx",name: '张三',age: 1
}
console.log(person);
// 自定义类型写法1
let demoList:Personns = [{ id: "xxxx", name: '张三', age: 18 },{ id: "xxxx", name: '李四', age: 5 },{ id: "xxxx", name: '王五', age: 1 },
]
014 props父传子数据
App.vue
<template><Person a="哈哈" b="嘿嘿" :list="personList"/>
</template>
<script lang="ts" setup name="APP">
import Person from './components/preson.vue'
import { reactive } from 'vue'
import { type Personns } from '@/types'
let personList = reactive<Personns>([{ id: 'xxxx', name: '张三', age: 18 },{ id: 'xxxx', name: '李四', age: 20 },{ id: 'xxxx', name: '王五', age: 22, x: 9 },
])
// let personList = 5
</script>
types/index.js
// 定义一个接口用于限制Person的具体属性
export interface PersonInter {id: string;name: string;age: number;x?: number;
}
// 自定义类型第1种写法
// export type Personns = Array<PersonInter>;
// 自定义类型第2种写法
export type Personns = PersonInter[];
preson.vue
<template><div><ul><li v-for="item in list" :key="item.id">{{ item.name }}</li></ul></div>
</template>
<script setup lang="ts" name="person">
import {withDefaults } from 'vue';
import { type Personns } from '@/types'
// 1.只接收list,不能输出
// defineProps(['list'])// 2.接收list,可以输出
/* let x = defineProps(['a', 'b', 'list'])
console.log(x.a) */// 2.接收list + 类型限制
/* defineProps<{ list: Personns,xxx:yyy }>() */// 3.接收list + 限制类型+限制必要性 + withDefaults指定默认值
// defineProps宏函数可以不用引用
withDefaults(defineProps<{ list?: Personns }>(), {list: () => [{ id: '默认id', name: '默认名字', age: 19 }]
})
</script>