网站优化的学习,企业站模板明细,想给孩子找点题做 都有什么网站,广州网页制作公司排名1.创建Vue3项目
1.运行创建项目命令
# 使用 npm
npm create vitelatest2、填写项目名称 3、选择前端框架 4、选择语法类型 5、按提示运行代码 不出意外的话#xff0c;运行之后应该会出现 下边这个页面 6.延伸学习#xff1a;对比webpack和vite#xff08;这个是面试必考…1.创建Vue3项目
1.运行创建项目命令
# 使用 npm
npm create vitelatest
2、填写项目名称 3、选择前端框架 4、选择语法类型 5、按提示运行代码 不出意外的话运行之后应该会出现 下边这个页面 6.延伸学习对比webpack和vite这个是面试必考题哦
1、Webpack会先打包然后启动开发服务器请求服务器时直接给予打包结果。
将所有的模块提前编译、打包进 bundle 中不管这个模块是否被用到随着项目越来越大打包启动的速度自然越来越慢。
使用 webpack 打包模式如下图 2、Vite直接启动开发服务器请求哪个模块再对该模块进行实时编译。
瞬间开启一个服务并不会先编译所有文件当浏览器用到某个文件时Vite 服务会收到请求然后编译后响应到客户端。
使用 Vite 打包模式如下图
3、vite 优点 vite 服务器启动速度比 webpack 快 由于vite启动的时候不需要打包也就无需分析模块依赖、编译所以启动速度非常快。当浏览器请求需要的模块时再对模块进行编译这种按需动态编译的模式极大缩短了编译时间当项目越大文件越多时vite的开发时优势越明显 vite热更新比webpack快 vite在HRM方面当某个模块内容改变时让浏览器去重新请求该模块即可而不是像webpack重新将该模块的所有依赖重新编译 vite使用esbuild(Go 编写) 预构建依赖而webpack基于nodejs, 比node快 10-100 倍 4、vite 缺点 生态不及webpack加载器、插件不够丰富 没被大规模重度使用会隐藏一些问题 2.初识项目目录以及main.js这个是最重要的文件欧
目录 import { createApp } from vue
// 全局样式
import ./style.css
import App from ./App.vue// 用create()方法把APP组件创建成一个项目挂载到#app的标签上
createApp(App).mount(#app)
看一下下边的index.html文件
!doctype html
html langenheadmeta charsetUTF-8 /link relicon typeimage/svgxml href/vite.svg /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleVite Vue/title/headbodydiv idapp/divscript typemodule src/src/main.js/script/body
/html
App.vue第一个组件
// 组件三大要素
// 结构
templatediv classfirstApphello world/div
/template
// 交互
script langts
// js or ts都是可以的 export default{name: App}
/script
// 样式
style scoped
.firstApp{font-size: 30px;height: 600;text-align: center;margin-top: 100px;
}
/style3.Vue3核心语法
3.1optionsAPI 与 compositionAPI
我们先看一下Vue3组件的代码
import { ref, computed } from vue;export default {setup() {const count ref(0);const doubleCount computed(() count.value * 2);function increment() {count.value;}return {count,doubleCount,increment};}
};
发现vue3的逻辑都在一块而vue2,数据方法都是分开的。
下边是组合式api的优势
可复用性 Composition API更适合实现代码的复用和逻辑的封装而Options API的代码复用性相对较差。逻辑组织Composition API将相关逻辑集中在一起更易于理解和维护而Options API将相关逻辑分散在不同的选项中不够清晰。代码重用 Composition API可以更灵活地重用逻辑代码而Options API的重用性较低。学习曲线Composition API相对Options API来说有一定的学习曲线但一旦掌握会发现其强大的灵活性和可复用性。
3.2.setup setup是vue3中的一个新的配置项值是一个函数。他是compositionAPI表演的舞台组件中所用到的数据/方法/计算属性/监视。。。等均配置在setup中 特点如下
setup函数返回对象中的内容可以直接在模板中使用。setup中访问this是undefinedsetup函数会在beforeCreate之前调用他是领先所有的钩子进行执行的。
template!-- 使用 --div{{a}}/divbutton clickchangeMsg点击/button
/template
script langts
// ts or js 都是可以的
export default{name : HelloWorld,beforeCreate(){console.log(beforeCreate);},setup(){console.log(setup,this); // setup 函数中的this是undefined,Vue3已经弱化this了// 声明let msg 新中国成立103周年 // 此时的数据不是响应式的function changeMsg(){console.log(我要改变,msg);alert(msg)}// 把变量交出去return {a:msg,changeMsg}}
}
/scriptstyle scoped/stylesetup的返回值 可以是对象也可以是函数
template!-- 使用 --div{{a}}/divbutton clickchangeMsg点击/button
/template
script langts
// ts or js 都是可以的
export default{name : HelloWorld,beforeCreate(){console.log(beforeCreate);},setup(){console.log(setup,this);// 声明let msg 新中国成立103周年 // 此时的数据不是响应式的function changeMsg(){console.log(我要改变,msg);alert(msg)}// 把变量交出去// return {a:msg,changeMsg}// 渲染函数写法1// return function(){// return 哈哈// }// 渲染函数写法2return () 哈哈}
}
/scriptstyle scoped/styledata(){},methods可以与setup共存
template!-- 使用 --div{{ a }}/divdiv{{ b }}/divbutton clickchangeMsg点击/buttonbutton clickchangeB点击2/button
/template
script langts
// ts or js 都是可以的
export default{name : HelloWorld,beforeCreate(){console.log(beforeCreate);},data() {return {b : 100,}},methods:{changeB(){this.b 1console.log(cccccc);}},setup(){console.log(setup,this);// 声明let msg 新中国成立103周年 // 此时的数据不是响应式的function changeMsg(){console.log(我要改变,msg);alert(msg)}// 把变量交出去return {a:msg,changeMsg}// 渲染函数写法1// return function(){// return 哈哈// }// 渲染函数写法2// return () 哈哈}
}
/scriptstyle scoped/stylesetup语法糖
template!-- 使用 --div{{ msg }}/divbutton clickchangeMsg点击/button
/template
script setup langts// 声明let msg 新中国成立103周年 // 此时的数据不是响应式的function changeMsg(){console.log(我要改变,msg);alert(msg)}
/scriptstyle scoped/style
使用 vite-plugin-vue-setup-extend 给组件起名字
第一步下载依赖vite-plugin-vue-setup-extend npm i vite-plugin-vue-setup-extend -D 第二步项目引入然后使用此插件 代码
import { defineConfig } from vite
import vue from vitejs/plugin-vue
// 引入插件
import VueSetupExtend from vite-plugin-vue-setup-extend
// 使用插件
// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),VueSetupExtend()],
})3.3.ref创建基本类型的响应式数据
template!-- 使用 --div{{ msg }}/divbutton clickchangeMsg点击/button
/template
script setup langts nameHelloWorld
import {ref} from vue// 声明let msg ref(新中国成立103周年) // 此时的数据是响应式的,返回的是refImpl的实例对象function changeMsg(){msg.value 新中国成立103周年,生日快乐console.log(我要改变,msg.value);alert(msg.value)}
/scriptstyle scoped/style
3.4.reactive创建对象类型的响应式数据
template!-- 使用 --div{{ msg.content }}/divbutton clickchangeMsg点击/buttonul!-- key其实相当于把后边的内容当成表达式去解析 --li v-foritem in arrList :keyitem.id{{ item.title }}/li/ul
/template
script setup langts nameHelloWorld
import {reactive} from vue// 声明let msg reactive({content:新中国成立103周年}) // 此时的数据是响应式的,返回的是Proxy的实例对象let arrList reactive([{id:1,title:中国银行},{id:2,title:工商银行},{id:3,title:建设银行}])function changeMsg(){msg.content 新中国成立103周年,生日快乐arrList[1].title 我的银行console.log(我要改变,msg,msg.content);alert(msg.content)}
/scriptstyle scoped/style/style
3.5.ref创建对象类型的响应式数据
template!-- 使用 --div{{ msg.content }}/divbutton clickchangeMsg点击/buttonul!-- key其实相当于把后边的内容当成表达式去解析 --li v-foritem in arrList :keyitem.id{{ item.title }}/li/ul
/template
script setup langts nameHelloWorld
import {ref} from vue// 声明let msg ref({content:新中国成立103周年}) // 此时的数据是响应式的,返回的是Proxy的实例对象let arrList ref([{id:1,title:中国银行},{id:2,title:工商银行},{id:3,title:建设银行}])function changeMsg(){msg.value.content 新中国成立103周年,生日快乐arrList.value[1].title 我的银行// console.log(我要改变,msg,msg.content);// alert(msg.value.content)}
/script
style scoped/style
这个说明ref可以定义响应式对象底层也是在使用Reactive,也就是proxy生成的.
3.6.ref与reactive
宏观角度 1.ref定义基本数据类型对象类型数据 2.reactive定义对象类型数据。 区别 1.ref创建的变量必须使用.value也可以使用volar插件自动添加.value 现在是Vue-official插件设置在下图。 使用原则 1.若需要一个基本类型的响应式数据必须使用ref. 2.若需要一个响应式对象层级不深ref,reactive都可以。 3.若需要一个响应式对象层级比较深推荐使用reactive。 注意点 当reactive定义的复杂数据类型时一个属性是ref类型时就不用value取值了会自动拆包了。 3.7.torefs与toref
toRefs把对象中多个属性转变成新的ref响应式对象
toRefs把对象中单个属性转变成新的ref响应式对象
templatediv名{{name}}/divdiv年龄{{age}}/divdivtoRef新名字{{ newName }}/divbutton clickchangeName修改名字/buttonbutton clickchangeAge修改名字/button
/template
script setup langts nameHelloWorldimport {reactive,toRefs,toRef} from vuelet person reactive({name:zhangsan,age:18})let {name,age} toRefs(person) // 把person里边的属性给领出来重新给搞成响应式我们现在有新的响应式数据name,age在下边的方法中我们可以发现只要改name,person.name也会跟着改let newName toRef(person,name)function changeName(){name.value ~}function changeAge(){age.value 10}
/script
style scoped/style
3.8.computed
页面使用6次但是只调用一次。这就是使用它的优势。
数据发生改变才进行调用。
template姓input typetext v-modelfirstNamebr/名input typetext v-modelsecondNamebr/姓名span{{fullName}}/spanbr/姓名span{{fullName}}/spanbr/姓名span{{fullName}}/spanbr/姓名span{{fullName}}/spanbr/姓名span{{fullName}}/spanbr/姓名span{{fullName}}/spanbr/
/template
script setup langts nameHelloWorld
import {ref,computed} from vue
let firstName ref(zhang)
let secondName ref(san)let fullName computed(() {console.log(使用);return firstName.value.slice(0,1).toUpperCase() firstName.value.slice(1) - secondName.value
})
/script
style scoped/style3.9.watch 只能监听以下四种
ref定义的数据。reactive定义的数据。函数返回一个值getter函数。一个包含以上内容的数组。
3.9.1 ref定义的基本数据类型
templatedivref定义基本类型的数字:{{ num }}/divdiv名{{person.name}}/divdiv年龄{{person.age}}/divbutton clickchangeName修改名字/buttonbutton clickchangeAge修改名字/buttonbutton clickchangeRef修改名字/button
/template
script setup langts nameHelloWorldimport {reactive,watch,ref} from vuelet person reactive({name:zhangsan,age:18})let num ref(0)// let numObj ref({// num:10// })function changeName(){person.name ~}function changeAge(){person.age 10}function changeRef(){num.value 1}const stopWatch watch(num,(val,oldVal) {console.log(获取新的值是,val,oldVal);if(val 3 ){stopWatch()}})console.log(1991,stopWatch);/script
style scoped/style3.9.2 ref定义的复杂数据类型
templatedivref定义复杂类型的数字:{{ numObj.num }}/divdivref定义复杂类型的数字:{{ numObj.name }}/divbutton clickchangeRefname修改名字/buttonbutton clickchangeRefnum修改数据/buttonbutton clickchangeRefObj修改整个/button
/template
script setup langts nameHelloWorldimport {watch,ref} from vuelet numObj ref({num:0,name:123})function changeRefname(){numObj.value.name ~~~~}function changeRefnum(){numObj.value.num 2}function changeRefObj(){numObj.value {num:1,name:456}}// 关心整个值,如果想要监听某一个属性deep:true 另外immediate:true 指的是一上来就开始监听watch(numObj,(val,oldVal) {console.log(获取新的值是,val,oldVal); // 除非整个对象被改不然新旧值是一样的因为地址没有改变},{deep:true,immediate:true})/script
style scoped/style3.9.3 reactive定义的复杂数据类型
templatedivreactive定义复杂类型的数字:{{ numObj.num }}/divdivreactive定义复杂类型的数字:{{ numObj.name }}/divdiv车牌子{{numObj.car.brand}} id:{{ numObj.car.id }}/div
button clickchangeRefbrand修改牌子/buttonbutton clickchangeRefname修改名字/buttonbutton clickchangeRefnum修改数据/buttonbutton clickchangeRefObj修改整个车/button
/template
script setup langts nameHelloWorldimport {watch,reactive} from vuelet numObj reactive({num:0,name:123,car:{id:1,brand:奥迪}})function changeRefname(){numObj.name ~~~~}function changeRefnum(){numObj.num 2}function changeRefbrand(){numObj.car.brand 长安}function changeRefObj(){// reactive定义的对象不可以整体修改numObj.car {brand:长安,id:456}// Object.assign(numObj.car,{brand:456,id:100})}// 监听某一个属性用getter函数拥有返回值的函数// watch(numObj.car ,(val,oldVal) {// console.log(获取新的值是,val,oldVal); // })watch(() numObj.car ,(val,oldVal) {console.log(获取新的值是,val,oldVal); },{deep:true})/script
style scoped/style// reactive定义的对象不可以整体修改 ,可以通过Object.assign()这个是重点欧
// reactive自动深度监听而且不能关闭
templatedivreactive定义复杂类型的数字:{{ numObj.num }}/divdivreactive定义复杂类型的数字:{{ numObj.name }}/divbutton clickchangeRefname修改名字/buttonbutton clickchangeRefnum修改数据/buttonbutton clickchangeRefObj修改整个/button
/template
script setup langts nameHelloWorldimport {watch,reactive} from vuelet numObj reactive({num:0,name:123})function changeRefname(){numObj.name ~~~~}function changeRefnum(){numObj.num 2}function changeRefObj(){// reactive定义的对象不可以整体修改// numObj {num:1,name:456}Object.assign(numObj,{name:456,num:1}) // 没有改变地址}// reactive定义的数据直接深度监听watch(numObj,(val,oldVal) {console.log(获取新的值是,val,oldVal); })/script
style scoped/style3.9.4 监听复杂数据中的某一个属性为基本数据类型
templatedivreactive定义复杂类型的数字:{{ numObj.num }}/divdivreactive定义复杂类型的数字:{{ numObj.name }}/divbutton clickchangeRefname修改名字/buttonbutton clickchangeRefnum修改数据/buttonbutton clickchangeRefObj修改整个/button
/template
script setup langts nameHelloWorldimport {watch,reactive} from vuelet numObj reactive({num:0,name:123})function changeRefname(){numObj.name ~~~~}function changeRefnum(){numObj.num 2}function changeRefObj(){// reactive定义的对象不可以整体修改// numObj {num:1,name:456}Object.assign(numObj,{name:456,num:1})}// 监听某一个属性用getter函数拥有返回值的函数watch(() numObj.name ,(val,oldVal) {console.log(获取新的值是,val,oldVal); })/script
3.9.5 监听复杂数据中的某一个属性为复杂数据类型
templatedivreactive定义复杂类型的数字:{{ numObj.num }}/divdivreactive定义复杂类型的数字:{{ numObj.name }}/divdiv车牌子{{numObj.car.brand}} id:{{ numObj.car.id }}/div
button clickchangeRefbrand修改牌子/buttonbutton clickchangeRefname修改名字/buttonbutton clickchangeRefnum修改数据/buttonbutton clickchangeRefObj修改整个车/button
/template
script setup langts nameHelloWorldimport {watch,reactive} from vuelet numObj reactive({num:0,name:123,car:{id:1,brand:奥迪}})function changeRefname(){numObj.name ~~~~}function changeRefnum(){numObj.num 2}function changeRefbrand(){numObj.car.brand 长安}function changeRefObj(){// reactive定义的对象不可以整体修改numObj.car {brand:长安,id:456}// Object.assign(numObj.car,{brand:456,id:100})}// 监听某一个属性用getter函数拥有返回值的函数// watch(numObj.car ,(val,oldVal) {// console.log(获取新的值是,val,oldVal); // })watch(() numObj.car ,(val,oldVal) {console.log(获取新的值是,val,oldVal); },{deep:true})/script
style scoped/style3.9.6 监听一个数组
templatedivreactive定义复杂类型的数字:{{ numObj.num }}/divdivreactive定义复杂类型的数字:{{ numObj.name }}/divdiv车牌子{{numObj.car.brand}} id:{{ numObj.car.id }}/div
button clickchangeRefbrand修改牌子/buttonbutton clickchangeRefname修改名字/buttonbutton clickchangeRefnum修改数据/buttonbutton clickchangeRefObj修改整个车/button
/template
script setup langts nameHelloWorldimport {watch,reactive} from vuelet numObj reactive({num:0,name:123,car:{id:1,brand:奥迪}})function changeRefname(){numObj.name ~~~~}function changeRefnum(){numObj.num 2}function changeRefbrand(){numObj.car.brand 长安}function changeRefObj(){// reactive定义的对象不可以整体修改numObj.car {brand:长安,id:456}// Object.assign(numObj.car,{brand:456,id:100})}// 监听某一个属性用getter函数拥有返回值的函数// watch(numObj.car ,(val,oldVal) {// console.log(获取新的值是,val,oldVal); // })watch([() numObj.car,() numObj.name] ,(val,oldVal) {console.log(获取新的值是,val,oldVal); },{deep:true})/script
style scoped/style3.10.watchEffect
watch和watchEffect都能监听只不过监听数据变化方式不一样watch需要明确监听的数据watchEffect不用明确指出监视的数据函数中用到哪些就监听哪些属性
templatedivreactive定义复杂类型的数字:{{ numObj.num }}/divdivreactive定义复杂类型的数字:{{ numObj.name }}/divdiv车牌子{{numObj.car.brand}} id:{{ numObj.car.id }}/div
button clickchangeRefbrand修改牌子/buttonbutton clickchangeRefname修改名字/buttonbutton clickchangeRefnum修改数据/buttonbutton clickchangeRefObj修改整个车/buttonbutton clickchangeAge1修改Age1/buttonbutton clickchangeAge2修改Age2/buttondivage1:{{ age1 }}/divdivage2:{{ age2 }}/div
/template
script setup langts nameHelloWorldimport {watch,reactive,watchEffect,ref} from vuelet age1 ref(2)let age2 ref(10)function changeAge1(){age1.value 10}function changeAge2(){age2.value 20}let numObj reactive({num:0,name:123,car:{id:1,brand:奥迪}})function changeRefname(){numObj.name ~~~~}function changeRefnum(){numObj.num 2}function changeRefbrand(){numObj.car.brand 长安}function changeRefObj(){// reactive定义的对象不可以整体修改numObj.car {brand:长安,id:456}// Object.assign(numObj.car,{brand:456,id:100})}// 监听某一个属性用getter函数拥有返回值的函数// watch(numObj.car ,(val,oldVal) {// console.log(获取新的值是,val,oldVal); // })watchEffect(() {console.log(获取新的值是,age1.value,age2.value); })/script
style scoped/style3.11.标签ref属性
作用用于注册模板引用。
用于普通Dom标签上获取的是Dom节点。用于组件标签上获取的是组件实例对象。
子组件
templatediv我是ref/divh2 reftitles北京/h2button clickgetDom点击获取Dom/button
/template
script setup langts nameHelloWorldimport {ref,defineExpose} from vuelet aaa ref(100)let bbb ref(200)let titles ref()function getDom(){console.log(获取Dom,titles.value);}defineExpose({aaa,bbb})
/script
style scoped/style
父组件
// 组件三大要素
// 结构
templateh2asdasd/h2button clickgetDom获取ref/buttonHelloWorld refhellos/HelloWorld
/template
// 交互
script setup langts nameApp
import HelloWorld from ./components/HelloWorld.vue
import {ref} from vue
let hellos ref()
function getDom(){console.log(父亲获取子组件,hellos.value);}
/script
// 样式
style scoped
.firstApp{font-size: 30px;height: 600;text-align: center;margin-top: 100px;
}
/style3.12.props
父传子通过属性传输子通过defineProps接收
父组件
// 组件三大要素
// 结构
templateHelloWorld refhellos ahaha bheihei :listpersonList/HelloWorld
/template
// 交互
script setup langts nameApp
import HelloWorld from ./components/HelloWorld.vue
import { reactive } from vue;
import {type Persons} from ./types/index
// reactive直接用泛型形式写比较优雅 reactivePerson,如果可有可无的属性y需要在接口中用?:去控制
let personList reactivePersons([{id:1,name:张三,age:18},{id:2,name:张四,age:19},{id:3,name:张五,age:20},
])
/script
// 样式
style scoped
.firstApp{font-size: 30px;height: 600;text-align: center;margin-top: 100px;
}
/style子组件
template
!-- div子组件{{ a }}/div --
ulli v-for item in list :keyitem.id{{ item.name }}/li
/ul
/template
script setup langts nameHelloWorld
// defineProps 是宏函数 不用非得引入
import { defineProps,withDefaults } from vue;
import { type Persons } from ../types;
// 只接受
// defineProps([list])// 接受list并限制类型
// defineProps{list:Persons}()// 接受list 并限制类型 限制必要性 指定默认值 ?指的是是否可传withDefaults(defineProps{list?:Persons}(),{list:() [{id:5,name:wang,age:40}]
})// 接受并保存
// let x defineProps([a,b,list])
// console.log(x);/script
style scoped/styletypes
// 定义接口 限制person的具体属性
export interface PersonInter {name:string,age:number,id:number,// y?:number
}// export type Persons ArrayPersonInter
export type Persons PersonInter[]3.13.生命周期
组件的生命周期创建挂载更新销毁
Vue2
beforeCreate created
beforeMounte mounted
beforeUpdate updated
beforeDestroy destroyed v-show 与 v-if 在这里有本质的区别 Vue3
setup 创建阶段
onBeforeMount(() {})
onMounted
onBeforeUpdate
onUpdated
onBeforeUnmount
onUnmounted 挂载顺序是先父后子再是子然后是父父子子父的顺序
template
!-- div子组件{{ a }}/div --
ulli v-for item in list :keyitem.id{{ item.name }}/li
/ul
/template
script setup langts nameHelloWorld
// defineProps 是宏函数 不用非得引入
import { defineProps,withDefaults,onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from vue;
import { type Persons } from ../types;
// 只接受
// defineProps([list])// 接受list并限制类型
// defineProps{list:Persons}()// 接受list 并限制类型 限制必要性 指定默认值 ?指的是是否可传withDefaults(defineProps{list?:Persons}(),{list:() [{id:5,name:wang,age:40}]
})onBeforeMount(() {console.log(挂载前);})onMounted(() {console.log(挂载后);
})onBeforeUpdate(() {console.log(更新前);})onUpdated(() {console.log(更新后);
})onBeforeUnmount(() {console.log(卸载前);})onUnmounted((){console.log(卸载后);
})
// 接受并保存
// let x defineProps([a,b,list])
// console.log(x);/script
style scoped/style3.14.自定义hooks useDog.ts
// defineProps 是宏函数 不用非得引入
import { reactive } from vue;
import axios from axios;
export default function(){let dogList reactivestring[]([https://images.dog.ceo/breeds/pembroke/n02113023_3337.jpg])// function getDog(){// // axios.get(https://images.dog.ceo/breeds/pembroke/n02113023_3337.jpg).then(// // response {// // console.log(response);// // },// // error {// // console.log(error);// // }// // )async function getDog(){try { let response await axios.get(https://dog.ceo/api/breed/pembroke/images/random); // 假设响应体有一个属性比如 message包含图片 URL // 注意这里的属性名应该根据您的实际 API 响应来调整 let dogUrl response.data.message; console.log(123,dogUrl);dogList.push(dogUrl); } catch (error) { console.error(Error fetching dog image URL:, error); } }return {getDog,dogList}
} useSum
// defineProps 是宏函数 不用非得引入
import { ref,onMounted,computed } from vue;export default function(){let sum ref(0)let bigSum computed(() {return sum.value*10}) function add(){sum.value 1}onMounted((){console.log(加载完成);})return {sum,add,bigSum}
}// 图片接口 https://dog.ceo/api/breed/pembroke/images/random
3.15. 回顾Ts
接口
// 定义接口 限制person的具体属性
export interface PersonInter {name:string,age:number,id:number
}// export type Persons ArrayPersonInter
export type Persons PersonInter[]页面使用接口
template
divTs/div
div{{ person.name }}/div
button clickchangeName改名字/button
/template
script setup langts nameHelloWorld
import { reactive } from vue;
// import { type PersonInter,type Persons } from ../types; // 下边写法更好
import type { PersonInter,Persons } from ../types;let person : PersonInter reactive({id:1,name:wang,age:60}) // ts
// 第一种写法
// let personList:ArrayPersonInter reactive([
// {id:1,name:wang,age:60},
// {id:2,name:wang1,age:60},
// {id:3,name:wang2,age:60},
// ])
// 第二种写法
// let personList:PersonInter[] reactive([
// {id:1,name:wang,age:60},
// {id:2,name:wang1,age:60},
// {id:3,name:wang2,age:60},
// ])
// 第三种写法
let personList:Persons reactive([{id:1,name:wang,age:60},{id:2,name:wang1,age:60},{id:3,name:wang2,age:60},
])
function changeName(){person.name aaaconsole.log(personList[0]);}/script
style scoped/style4.路由
4.1初体验 1.导航区展示区布局好。 2.生成路由器。 3.制定路由规则。 4.形成一个个的Vue文件。 router/index
// 创建路由器// 第一步引入createRouter
import { createRouter,createWebHistory } from vue-router;
// 引入一个个组件
import Home from ../components/Home.vue
import About from ../components/About.vue
import News from ../components/News.vue// 第二步 创建路由器
const router createRouter({// 路由模式history:createWebHistory(),// 路由规则routes:[{path:/home,component:Home},{path:/about,component:About},{path:/news,component:News}]
})// 暴露
export default routermain.ts
import { createApp } from vue
// import ./style.css
import App from ./App.vue// 引入路由器
import router from ./router/indexlet app createApp(App)
app.use(router)
app.mount(#app)App.vue
// 组件三大要素
// 结构
template
divh2Vue路由测试/h2div classnavigateRouterLink to/home classitem active-classjihuoshi首页/RouterLinkRouterLink to/news classitem active-classjihuoshi新闻/RouterLinkRouterLink to/about classitem active-classjihuoshi关于/RouterLink/divdiv classmain-content此处以后需要展示各种内容RouterView/RouterView/div
/div
/template
// 交互
script setup langts nameApp
import { RouterView,RouterLink } from vue-router;
/script
// 样式
style scoped
.navigate{.item{margin-left: 30px;}.jihuoshi{color: red;}
}
.main-content{height: 200px;background: rgb(213, 210, 210);/* opacity: 0.2; */
}
/style4.2注意点工程化 1.路由组件通常放在pages或者views文件下一般组件放在components 2.通过点击导航视觉效果上消失了的路由默认是销毁的需要的时候需要再去挂载。 4.3to的两种写法
RouterLink to/home classitem active-classjihuoshi首页/RouterLinkRouterLink to/news classitem active-classjihuoshi新闻/RouterLinkRouterLink to/about classitem active-classjihuoshi关于/RouterLinkRouterLink :to{name:news} classitem active-classjihuoshi新闻/RouterLinkRouterLink :to{path:/home} classitem active-classjihuoshi首页/RouterLinkRouterLink :to{name:about} classitem active-classjihuoshi关于/RouterLink // 创建路由器// 第一步引入createRouter
import { createRouter,createWebHistory,createWebHashHistory } from vue-router;
// 引入一个个组件
import Home from ../components/Home.vue
import About from ../components/About.vue
import News from ../components/News.vue// 第二步 创建路由器
const router createRouter({// 路由模式history:createWebHashHistory(),// 路由规则routes:[{name:home,path:/home,component:Home},{name:about,path:/about,component:About},{name:news,path:/news,component:News}]
})// 暴露
export default router4.4路由的工作模式 History模式 url更加美观无#更贴近传统的网站URL缺点需要服务器配合处理路径问题否则刷新会有404 Vue2:mode:history Vue3:history:createWebHistory() React:BrowserRouter Hash模式 兼容性更好不需要服务器处理路径 Vue2:mode:hash Vue3:history:createWebHashHistory() 4.5嵌套路由
// 创建路由器// 第一步引入createRouter
import { createRouter,createWebHistory,createWebHashHistory } from vue-router;
// 引入一个个组件
import Home from ../components/Home.vue
import About from ../components/About.vue
import News from ../components/News.vueimport Details from ../components/Details.vue// 第二步 创建路由器
const router createRouter({// 路由模式history:createWebHashHistory(),// 路由规则routes:[{name:home,path:/home,component:Home},{name:about,path:/about,component:About},{name:news,path:/news,component:News,children:[{path:details,component:Details},]}]
})// 暴露
export default routernews.vue
templatediv!-- 导航区 --ulli v-foritem in newsList :keyitem.idRouterLink :to{path:/news/details}{{ item.title }}/RouterLink/li/ul/divdiv新闻内容RouterView/RouterView/div
/template
script setup langts nameNews
import { reactive } from vue;
import { RouterLink, RouterView } from vue-router;const newsList reactive([{id:1,title:sadasda1,content:西瓜1},{id:2,title:sadasda2,content:西瓜2},{id:3,title:sadasda3,content:西瓜3},{id:4,title:sadasda4,content:西瓜4},
])
/script
4.6query传参
templatediv!-- 导航区 --ulli v-foritem in newsList :keyitem.id!-- 第一种写法 --!-- RouterLink :to/news/details?item${item.content}{{ item.title }}/RouterLink --!-- 第二种写法 --RouterLink :to{path:/news/details,query:{item:item.content}}{{ item.title }}/RouterLink/li/ul/divdiv新闻内容RouterView/RouterView/div
/template
script setup langts nameNews
import { reactive } from vue;
import { RouterLink, RouterView } from vue-router;const newsList reactive([{id:1,title:sadasda1,content:西瓜1},{id:2,title:sadasda2,content:西瓜2},{id:3,title:sadasda3,content:西瓜3},{id:4,title:sadasda4,content:西瓜4},
])
/script
templatediv{{ query.item }}/div
/template
script setup langts nameDetails
import { toRefs } from vue;
import { useRoute } from vue-router;
let route useRoute()
// 必须使用toRefs ,否则失去了响应式
let {query} toRefs(route)
console.log(使用路由,route.query.item);/script 4.6params传参
templatediv!-- 导航区 --ulli v-foritem in newsList :keyitem.id!-- 第一种写法 --!-- RouterLink :to /news/details/${item.content}{{ item.title }}/RouterLink --!-- 第一种写法 --RouterLink :to {name:details,params:{item:item.content}}{{ item.title }}/RouterLink/li/ul/divdiv新闻内容RouterView/RouterView/div
/template
script setup langts nameNews
import { reactive } from vue;
import { RouterLink, RouterView } from vue-router;const newsList reactive([{id:1,title:sadasda1,content:西瓜1},{id:2,title:sadasda2,content:西瓜2},{id:3,title:sadasda3,content:西瓜3},{id:4,title:sadasda4,content:西瓜4},
])
/script templatediv{{ route.params.item }}/div
/template
script setup langts nameDetails
// import { toRefs } from vue;
import { useRoute } from vue-router;
let route useRoute()
// 必须使用toRefs ,否则失去了响应式
// let {params} toRefs(route)
// console.log(使用路由,route.query.item);/script 备注1传递params参数时使用to,必须使用name,不能使用path 备注2传递params参数时候需要提前在路由规则处占位 {name:news,path:/news,component:News,children:[{path:details/:item,component:Details,name:details}]} 4.7路由的props传参
4.7.1路由加上props为true,只能处理params参数
{name:news,path:/news,component:News,children:[{path:details/:item,component:Details,name:details,props:true}]} 页面不再使用useRoute了
templatediv{{ item }}/div
/template
script setup langts nameDetails
// import { toRefs } from vue;
// import { useRoute } from vue-router;
// import { toRefs } from vue;
// let route useRoute()
// let {params} toRefs(route)
// 一步搞定 其实我们可以认为路由收到params参数的时候如果props为true,那么就会放在Vue组件上有意思
defineProps([item])
// 必须使用toRefs ,否则失去了响应式
// let {params} toRefs(route)
// console.log(使用路由,route.query.item);/script 4.7.2处理query参数
{name:news,path:/news,component:News,children:[{path:details,component:Details,name:details,props(route){return route.query}}]}
templatediv{{ item }}/div
/template
script setup langts nameDetails
// import { toRefs } from vue;
// import { useRoute } from vue-router;
// // import { toRefs } from vue;
// let route useRoute()
// let {query} toRefs(route)
defineProps([item])
// 必须使用toRefs ,否则失去了响应式
// let {params} toRefs(route)
// console.log(使用路由,route.query.item);/script 4.7.3 自己决定传什么参数
{name:news,path:/news,component:News,children:[{path:details,component:Details,name:details,props(route){return {item:自己定义}}}]} 总结一般组件可以自己写标签属性自己加props自己传路由组件呢就是在上边加上喽。本质就是这样的。
4.8 replace属性
replace其实就是替换push就是加入栈了方便用户在页面上进行页面切换。
RouterLink replace to/home classitem active-classjihuoshi首页/RouterLinkRouterLink replace to/news classitem active-classjihuoshi新闻/RouterLinkRouterLink replace to/about classitem active-classjihuoshi关于/RouterLink 4.9 编程式导航 import {useRouter} from vue-route let router useRouter() router.push(/news) router.replace(/news) 传参就按照to属性去写 templatediv!-- 导航区 --ulli v-foritem in newsList :keyitem.idbutton clicktoNews(item)点我带你编程式导航并传参/button!-- 第一种写法 --!-- RouterLink :to /news/details/${item.content}{{ item.title }}/RouterLink --!-- 第一种写法 --RouterLink :to {name:details,query:{item:item.content,}}{{ item.title }}/RouterLink/li/ul/divdiv新闻内容RouterView/RouterView/div
/template
script setup langts nameNews
import { reactive } from vue;
import { RouterLink, RouterView,useRouter } from vue-router;interface NewsInter{content:string
}const newsList reactive([{id:1,title:sadasda1,content:西瓜1},{id:2,title:sadasda2,content:西瓜2},{id:3,title:sadasda3,content:西瓜3},{id:4,title:sadasda4,content:西瓜4},
])const router useRouter()
function toNews(item:NewsInter){router.push({name:details,query:{item:item.content,}})
}
/script
4.10 路由的重定向
// 创建路由器// 第一步引入createRouter
import { createRouter,createWebHistory,createWebHashHistory } from vue-router;
// 引入一个个组件
import Home from ../components/Home.vue
import About from ../components/About.vue
import News from ../components/News.vueimport Details from ../components/Details.vue// 第二步 创建路由器
const router createRouter({// 路由模式history:createWebHashHistory(),// 路由规则routes:[{name:home,path:/home,component:Home},{name:about,path:/about,component:About},{path:/,redirect:/news},{name:news,path:/news,component:News,children:[{path:details,component:Details,name:details,props(route){return {item:route.query.item}}}]},]
})// 暴露
export default router5.pinia 符合直觉的Vue.js状态管理库大白话就是项目帮助你全局存数据 准备一个页面写的的比较简单。
templatedivdiv我是数字{{num}}/divbutton clickgetWords获取撩妹情话/buttondiv{{ wordss }}/div/div
/template
script setup langts
import {ref} from vue
import axios from axios;
let num ref(110)
let wordss refstring()async function getWords(){// 两次结构赋值再加重命名let {data:{content:title}} await axios.get(https://api.uomg.com/api/rand.qinghua?formatjson)wordss.value title}5.1 搭建pinia环境
第一步 npm i pinia
第二步 main.js
import { createApp } from vue
// import ./style.css
import App from ./App.vue// 引入路由器
import router from ./router/index// 引入pinia
import {createPinia} from pinialet app createApp(App)// 创建pinia
const pinia createPinia()
// 项目使用pinia
app.use(pinia)app.use(router)
app.mount(#app)5.2 简单存储加上读取 import { defineStore } from pinia;export const useCountStore defineStore(count,{// 真正存储的地方state(){return {sum:6}}
})
templatedivdiv我是数字{{countStore.sum}}/divbutton clickgetWords获取撩妹情话/buttondiv{{ wordss }}/div/div
/template
script setup langts
import {ref} from vue
import axios from axios;
// 引入 useCountStore
import {useCountStore} from ../store/count// 使用countStore
let countStore useCountStore()
// reactive 内部 有ref ,自动拆包不用加value
console.log(获取内容, countStore.sum);let wordss refstring()async function getWords(){// 两次结构赋值再加重命名let {data:{content:title}} await axios.get(https://api.uomg.com/api/rand.qinghua?formatjson)wordss.value title}/script 5.3 修改数据的三种方式
import { defineStore } from pinia;export const useCountStore defineStore(count,{actions:{editSum(value:number){this.$state.sum valuethis.$state.country 中国this.$state.name 张三}},// 真正存储的地方state(){return {sum:6,country:china,name:zhansan}}
})
templatedivdiv我是数字{{countStore.sum}}/divdiv国家是{{countStore.country}}/divdiv名字是{{countStore.name}}/divbutton clickaddSumsum10/buttonbrbutton clickgetWords获取撩妹情话/buttondiv{{ wordss }}/div/div
/template
script setup langts
import {ref} from vue
import axios from axios;
// 引入 useCountStore
import {useCountStore} from ../store/count// 使用countStore
let countStore useCountStore()function addSum(){// 第一种修改方式// countStore.sum 10// countStore.country 中国// countStore.name 张三// 第二种批量修改 数量多的时候需要用效能更高一些// countStore.$patch({// sum:countStore.sum 10,// country:中国,// name:张三// })// 第三种 actioncountStore.editSum(10)
}
// reactive 内部 有ref ,自动拆包不用加value
console.log(获取内容, countStore.sum);let wordss refstring()async function getWords(){// 两次结构赋值再加重命名let {data:{content:title}} await axios.get(https://api.uomg.com/api/rand.qinghua?formatjson)wordss.value title}/script actions复用最舒服
5.4 storeToRefs
templatedivdiv我是数字{{sum}}/divdiv国家是{{country}}/divdiv名字是{{name}}/divbutton clickaddSumsum10/buttonbrbutton clickgetWords获取撩妹情话/buttondiv{{ wordss }}/div/div
/template
script setup langts
import {ref,toRefs } from vue
import axios from axios;
// 引入 useCountStore
import {useCountStore} from ../store/count
import { storeToRefs } from pinia;// 使用countStore
let countStore useCountStore()
// 千万别用这样太累了
// let {sum,country,name} toRefs(countStore)// 需要过滤一下
let {sum,country,name} storeToRefs(countStore)function addSum(){// 第一种修改方式// countStore.sum 10// countStore.country 中国// countStore.name 张三// 第二种批量修改 数量多的时候需要用效能更高一些// countStore.$patch({// sum:countStore.sum 10,// country:中国,// name:张三// })// 第三种 actioncountStore.editSum(10)
}
// reactive 内部 有ref ,自动拆包不用加value
console.log(获取内容, countStore.sum);let wordss refstring()async function getWords(){// 两次结构赋值再加重命名let {data:{content:title}} await axios.get(https://api.uomg.com/api/rand.qinghua?formatjson)wordss.value title}/script 5.5 getters 的 使用
本质就是修饰一下state的数据形成一个新的state,从而进行使用修饰过后的store数据。
import { defineStore } from pinia;export const useCountStore defineStore(count,{actions:{editSum(value:number){this.$state.sum valuethis.$state.country 中国this.$state.name 张三}},// 真正存储的地方state(){return {sum:6,country:china,name:zhansan}},getters:{bigSum:(state) state.sum*10,// bigSum(state){// return state.sum*10// },daXie():string{return this.country.toUpperCase()}}
})
templatedivdivgetters:{{ bigSum }}/divdiv我是数字{{sum}}/divdiv国家是{{country}}/divdiv国家名{{daXie}}/divdiv名字是{{name}}/divbutton clickaddSumsum10/buttonbrbutton clickgetWords获取撩妹情话/buttondiv{{ wordss }}/div/div
/template
script setup langts
import {ref,toRefs } from vue
import axios from axios;
// 引入 useCountStore
import {useCountStore} from ../store/count
import { storeToRefs } from pinia;// 使用countStore
let countStore useCountStore()
// 千万别用这样太累了
// let {sum,country,name} toRefs(countStore)// 需要过滤一下
let {sum,country,name,bigSum,daXie} storeToRefs(countStore)function addSum(){// 第一种修改方式// countStore.sum 10// countStore.country 中国// countStore.name 张三// 第二种批量修改 数量多的时候需要用效能更高一些// countStore.$patch({// sum:countStore.sum 10,// country:中国,// name:张三// })// 第三种 actioncountStore.editSum(10)
}
// reactive 内部 有ref ,自动拆包不用加value
console.log(获取内容, countStore.sum);let wordss refstring()async function getWords(){// 两次结构赋值再加重命名let {data:{content:title}} await axios.get(https://api.uomg.com/api/rand.qinghua?formatjson)wordss.value title}/script 5.5 $subscribe 监听 store里边的数据修改
其实本质就是watch,监听数据变化的
templatedivdivgetters:{{ bigSum }}/divdiv我是数字{{sum}}/divdiv国家是{{country}}/divdiv国家名{{daXie}}/divdiv名字是{{name}}/divbutton clickaddSumsum10/buttonbrbutton clickgetWords获取撩妹情话/buttondiv{{ wordss }}/div/div
/template
script setup langts
import {ref,toRefs } from vue
import axios from axios;
// 引入 useCountStore
import {useCountStore} from ../store/count
import { storeToRefs } from pinia;// 使用countStore
let countStore useCountStore()
// 订阅监听
countStore.$subscribe((mutate,state){console.log(数据发生变化了,mutate,state);}) 5.6 store 的 组合式写法
import { defineStore } from pinia;// export const useCountStore defineStore(count,{
// actions:{
// editSum(value:number){
// this.$state.sum value
// this.$state.country 中国
// this.$state.name 张三
// }
// },
// // 真正存储的地方
// state(){
// return {
// sum:6,
// country:china,
// name:zhansan
// }
// },
// getters:{
// bigSum:(state) state.sum*10,
// // bigSum(state){
// // return state.sum*10
// // },
// daXie():string{
// return this.country.toUpperCase()
// }
// }
// }) import {ref} from vue// 相当于setup
export const useCountStore defineStore(count,() {// 相当于stateconst sum ref(6)const country ref(china)const name ref(zhansan)const bigSum ref(0)bigSum.value sum.value * 10const daXie ref()daXie.value country.value.toUpperCase()// 相当于actionsfunction editSum(value:number){sum.value valuecountry.value 中国name.value 张三}return {sum,country,name,editSum,bigSum,daXie}})
6.组件通信
6.1 props 父传子 --非函数传值 1.父组件 传值 HomeChild afather/ 2.子组件 收值 defineProps([a]) 6.2 props子传父 -- 函数传值 1.父组件 HomeChild afather :sendToygetToy/ function getToy(value:string){ console.log(value); childToy.value value } 2.子组件 button clicksendToy(toy)告诉父亲/button 6.3 自定义事件 (专门用来子传父) 1.子组件定义自定义事件并在合适的时机触发 const emit defineEmits([childEvent]) function sendBook(){ emit(childEvent,数学) } 2.父组件调用此自定义函数并且拿着一个回调函数接收这个值 HomeChild afather :sendToygetToy childEventqwe/ function qwe(val:string){ console.log(111111111111,val); } 6.4 mitt
pubsub;$bus;mitt
提前绑好事件提前订阅事件
提供数据合适时机触发事件发布消息 第一步 npm i mitt
第二步 引入 // 引入
import mitt from mitt// 创造
let emitter:any mitt()
console.log(获取2m,emitter);emitter.on(test1,(value:number){console.log(asd,被调用,value);
})
setInterval(() {emitter.emit(test1,10)
},1000)
setTimeout(() {emitter.all.clear()
},3000)
// 暴漏
export default emitter import { createApp } from vue
// import ./style.css
import App from ./App.vue// 引入路由器
import router from ./router/indeximport emitter from ../src/utils/emitter// 引入pinia
import {createPinia} from pinialet app createApp(App)// 创建pinia
const pinia createPinia()
// 项目使用pinia
app.use(pinia)
app.use(emitter)
app.use(router)
app.mount(#app)另外记得在在组件卸载的时候把emitter事件取消掉 emitter.off(text1) // 避免内存泄漏 6.5 v-model
父组件
templatedivabout页面!-- v-model用在html标签上 --!-- input typetext v-modelname/ --!-- (HTMLInputElement$event.target) HTMLInputElement 断言是html元素--!-- input typetext :valuename inputname (HTMLInputElement$event.target).value/ --!-- v-model 用在组件上 --div父组件呈现{{name}}/div!-- MyInput v-modelname / --!-- MyInput :modelValuename update:modelValuename $event/ --!-- 一定记得input --!-- 自定义写法 --MyInput v-model:ZIDINGYIname //div
/template
script langts setup nameAbout
import {onUpdated, ref} from vueimport MyInput from ../components/mynput.vue;let nameref(张三)
onUpdated((){console.log(12121, name.value);
})
/script
子组件
!-- templatebr子组件input typetext :valuemodelValueinputemit(update:modelValue,(HTMLInputElement$event.target).value)/
/template
script setup langts nameMyInput
defineProps([modelValue])
let emit defineEmits([update:modelValue])
/script --templatebr子组件input typetext :valueZIDINGYIinputemit(update:ZIDINGYI,(HTMLInputElement$event.target).value)/
/template
script setup langts nameMyInput
defineProps([ZIDINGYI])
let emit defineEmits([update:ZIDINGYI])
/script
注意看自定义的写法 其实Ui底层大量使用了modelValue 以及update-modelValude 对于原生事件$event就是事件对象 需要target 对于自定义事件$event就是触发事件时所传递的数据 不需要target 本质使用了父传子子传父
6.6 $attrs
祖孙传值
MyInput v-model:ZIDINGYIname ahaha v-bind{b:100,c:200}/
看一下v-bind,相当于传了多了属性
GrandChild v-bind$attrs/
templatediv孙{{ $attrs }}/div
/template
script langts nameSun/script 6.7 $refs,$parents
$refs 父传子
templatediv孙{{ $attrs }}div密码是{{password}}/div/div
/template
script setup langts nameSun
import {ref} from vue
let password ref(123)
defineExpose({password})
/script
GrandChild refgrandChild v-bind$attrs/import { onMounted,ref } from vue;
import GrandChild from ./SunZi.vue
let grandChild ref()
onMounted(() {console.log(555555555555,grandChild.value.password 456);})
在父组件可以获取多了子组件进行值的修改
$parents 子传父 1.defineExpose({parentNum}) 父组件暴漏数据 2.$parent.parentNum 子组件直接使用 6.8 provide ,inject
本质不打扰子组件
祖先组件
import {onUpdated, ref,provide,reactive} from vue
let car reactive({brand:奥迪,num:10
})
provide(car,car) 孙组件
import {onMounted, ref,inject} from vue
// {brand:宝贝,num:0} 给默认值解决爆红问题
let car inject(car,{brand:宝贝,num:0})
祖先组件
import {onUpdated, ref,provide,reactive} from vueimport MyInput from ../components/mynput.vue;
let money ref(10013)
function updateMoney(value:number){money.value value
}
provide(money,{money,updateMoney}) 孙组件
templatediv孙button clickupdateMoney(6)修改爷爷的钱/button/div
/template
script setup langts nameSun
import {onMounted, ref,inject} from vue
let {money,updateMoney} inject(money,{money:0,updateMoney:(params:number){console.log(params)}})
6.9 slot
默认插槽
templateGrandChildspan你好/span/GrandChildGrandChildspan你好a啊/span/GrandChildGrandChildspan天气好啊好a啊/span/GrandChild
/template
script setup langts nameMyInput
import GrandChild from ./SunZi.vue
/script
templatediv孙slot/slot/div
/template
script setup langts nameSun/script 具名插槽
其实默认插槽 namedefault template!-- 第一种写法 --!-- GrandChild template v-slot:s2span你好/span/templatetemplate v-slot:s1span,好啊/span/template/GrandChild --GrandChild template #s2span你好/span/templatetemplate #s1span,好啊/span/template/GrandChild
/template
script setup langts nameMyInput
import GrandChild from ./SunZi.vue
/script
templatediv孙slot names2/slotslot names1/slotslot names3/slot/div
/template
script setup langts nameSun/script 作用域插槽
数据在子组件上怎么显示由父亲决定
template!-- 第一种写法 --!-- GrandChild template v-slotparamsspan{{ params.age }}/span/template/GrandChild --GrandChild template v-slot:qwe{age} span{{ age }}/span/template/GrandChild!-- 当无name那就是默认名default --!-- GrandChild template v-slot:default{age} span{{ age }}/span/template/GrandChildGrandChild template #default{age} span{{ age }}/span/template/GrandChild --
/template
script setup langts nameMyInput
import GrandChild from ./SunZi.vue
/script
templatediv孙slot age18 nameqwe/slot/div
/template
script setup langts nameSun/script 组件关系传递方式父传子 1.props 2.v-model 3.$refs 4.默认插槽具名插槽 子传父 1.props 2.自定义事件 3.v-model 4.$parent 5.作用域插槽 祖传孙孙传祖 1.$attrs 2.provide,inject 兄弟之间传输任意组件传输 1.mitt 2.pinia
7.其他API
7.1 shallowRef与shallowReactive
shallowRef 作用创建一个响应式数据但只对顶层属性进行响应式处理。 用法let myVal shallowRef(initialValue) 特点只是跟踪引用值的变化不关心值内部的属性变化。 shallowReactive 作用创建一个响应式数据但只对顶层属性进行响应式处理对象内部嵌套属性则不会变成响应式。 用法let myVal shallowReactive({......}) 特点只是跟踪引用值的变化不关心值内部的属性变化。 7.2 readonly与shallowReadonly
readonly 作用用于创建一个对象的深只读副本。 用法const original reactive({...}) const readOnlyCopy readonly(original) 特点 对象的所有嵌套属性都将变成只读状态。 任何修改对象被阻止 应用场景 创建不可变的状态快照。 保护全局状态或者配置不被修改。 shallowReadonly 浅层只读深层可以改 7.3 toRow与markRaw
toRow 作用用于获取一个响应式的数据对象的原始对象返回的也不再是响应式不触发视图更新。 场景不想让别人改。 markRaw 作用标记一个对象使其永远不会变成响应式的。 例如使用mock.js时为了防止误把mock.js变成响应式对象。可以使用markRaw去标记mock.js. 7.4 customRef
后续内容继续补充