首页IT科技vue3.js([Vue]Vue3学习笔记(尚硅谷))

vue3.js([Vue]Vue3学习笔记(尚硅谷))

时间2025-07-10 10:23:16分类IT科技浏览5119
导读:文章目录 🥽 前言 🥽 创建Vue3项目 🌊 vue-cli 🌊 vite 🥽 项目结构 🥽 Vue3开发者工具的安装 🥽 初...

文章目录

🥽 前言 🥽 创建Vue3项目 🌊 vue-cli 🌊 vite 🥽 项目结构 🥽 Vue3开发者工具的安装 🥽 初识setup 🥽 ref 函数 🥽 reactive函数 🥽Vue3.0中的响应式原理 🌊 vue2.x的响应式 🌊 Vue3.0的响应式 🥽 reactive对比ref 🥽 setup的两个注意点 🥽 computed函数 🥽 watch函数 🥽 watchEffect函数 🥽 生命周期 🥽 自定义hook函数 🥽 toRef 🥽 shallowReactive 与 shallowRef 🥽 readonly 与 shallowReadonly 🥽 toRaw 与 markRaw 🥽 customRef 🥽 provide 与 inject 🥽 响应式数据的判断 🥽 Composition API 的优势 🌊 Options API (配置式API)存在的问题 🌊 Composition API (组合式API)的优势 🥽 Fragment 🥽 Teleport 🥽 Suspense 🥽 Vue3全局API的转移 🥽 Vue3其他改变

🥽 前言

本笔记根据如下笔记和视频进行整理

老师的课件笔记              ,不含视频 https://www.aliyundrive.com/s/B8sDe5u56BU

笔记在线版: https://note.youdao.com/s/5vP46EPC

视频:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通

🥽 创建Vue3项目

🌊 vue-cli

使用vue-cli创建Vue3项目                     ,需要确保vue-cli版本在4.5.0以上              。

## 查看@vue/cli版本        ,确保@vue/cli版本在4.5.0以上 vue --version vue -V ## 安装或者升级@vue/cli npm install -g @vue/cli

使用vue-cli创建Vue3项目

vue create vue3_study

🌊 vite

vite创建Vue3项目步骤:

## 创建工程 npm init vite-app <project-name> ## 进入工程目录 cd <project-name> ## 安装依赖 npm install ## 运行 npm run dev npm init vite-app vue3_study_vite cd vue3_study_vite npm i npm run dev

🥽 项目结构

使用的为vue-cli创建的项目

src\main.js

// 引入的为一个名为createApp的工厂函数       ,不再是Vue构造函数 import { createApp } from vue import App from ./App.vue // 创建应用实例对象                     ,类似于Vue2中的vm               ,但是更“轻              ”       ,并挂载根标签 createApp(App).mount(#app)

src\App.vue

<template> <!-- Vue3组件中的模板结构可以没有根标签 --> <img alt="Vue logo" src="./assets/logo.png"> <HelloWorld msg="Welcome to Your Vue.js App"/> </template>

🥽 Vue3开发者工具的安装

可参考:[Vue]开发环境搭建

🥽 初识setup

setup是Vue3.0中一个新的配置项                     ,值为一个函数                     。setup是所有Composition API(组合API)“ 表演的舞台                      ”        。组件中所用到的:数据              、方法                     、计算属性等等               ,均要配置在setup中       。

setup函数的两种返回值:

若返回一个对象,则对象中的属性        、方法, 在模板中均可以直接使用                     。 <template> <h1>个人介绍</h1> <h2>name: {{name}}</h2> <h2>age: {{age}}</h2> <button @click="sayHello">打招呼</button> </template> <script> export default { name: App, // 测试setup, 不考虑响应式 setup() { // 数据 let name = ZS let age = 22 // 方法 function sayHello() { alert(`my name is ${name}, I am ${age}, hello`) } // 返回一个对象 return { name, age, sayHello } } } </script> 若返回一个渲染函数:则可以自定义渲染内容               。 <template> <h1>个人介绍</h1> <h2>name: {{name}}</h2> <h2>age: {{age}}</h2> <button @click="sayHello">打招呼</button> </template> <script> import {h} from vue // 导入渲染函数 export default { name: App, // 测试setup, 不考虑响应式 setup() { // 数据 let name = ZS let age = 22 // 方法 function sayHello() { alert(`my name is ${name}, I am ${age}, hello`) } // 返回一个对象 // return { // name, // age, // sayHello // } // 返回一个函数(渲染函数) // h1为渲染到页面的标签                     ,hello world为渲染内容 // h1为渲染到页面的标签                      ,hello world为渲染内容 return ()=>{ return h(h1, hello world) } } } </script>

在Vue3中仍然可以使用Vue2的配置项

<template> <h1>个人介绍</h1> <h2>name: {{name}}</h2> <h2>age: {{age}}</h2> <h2>sex: {{sex}}</h2> <button @click="sayHello">打招呼 vue3</button> <button @click="sayWelcome">打招呼 vue2</button> </template> <script> export default { name: App, data() { return { sex: male } }, methods: { sayWelcome() { alert(hello world vue2) } }, // 测试setup, 不考虑响应式 setup() { // 数据 let name = ZS let age = 22 // 方法 function sayHello() { alert(`my name is ${name}, I am ${age}, hello`) } // 返回一个对象 return { name, age, sayHello } } } </script>

setup尽量不要与Vue2.x配置混用       。Vue2.x配置(data       、methos                     、computed…)中可以访问到setup中的属性               、方法                     。但在setup中不能访问到Vue2.x配置(data       、methos                     、computed…)               。

<template> <h1>个人介绍</h1> <h2>name: {{name}}</h2> <h2>age: {{age}}</h2> <h2>sex: {{sex}}</h2> <button @click="sayHello">打招呼 vue3</button> <button @click="sayWelcome">打招呼 vue2</button> <button @click="test1">vue2配置项读取setup属性方法</button> <button @click="test2">setup配置项读取vue2配置项属性方法</button> </template> <script> export default { name: App, data() { return { sex: male } }, methods: { sayWelcome() { alert(hello world vue2) }, test1() { console.log(this.name) console.log(this.age) console.log(this.sayHello) } }, // 测试setup, 不考虑响应式 setup() { // 数据 let name = ZS let age = 22 // 方法 function sayHello() { alert(`my name is ${name}, I am ${age}, hello`) } function test2() { console.log(this.sex) console.log(this.sayWelcome) } // 返回一个对象 return { name, age, sayHello, test2, } } } </script>

Vue2配置项如果与setup中的属性或方法冲突,setup优先。即发生冲突时              ,以Vue3为主                     。

<template> <h1>a: {{a}}</h1> </template> <script> export default { name: App, data() { return { a: 100 } }, // 测试setup, 不考虑响应式 setup() { // 数据 let a = 200 // 返回一个对象 return { a } } } </script>

setup不能是一个async函数                      ,因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性                      。(后期也可以返回一个Promise实例        ,但需要Suspense和异步组件的配合)

🥽 ref 函数

作用: 定义一个响应式的数据 语法: const xxx = ref(initValue) 创建一个包含响应式数据的引用对象(reference对象              ,简称ref对象)。 JS中操作数据: xxx.value 模板中读取数据: 不需要.value                     ,直接:<div>{{xxx}}</div> 备注: 接收的数据可以是:基本类型               、也可以是对象类型              。 基本类型的数据:响应式依然是靠Object.defineProperty()的get与set完成的                      。 对象类型的数据:内部 “ 求助        ” 了Vue3.0中的一个新函数—— reactive函数        。 <template> <h1>个人信息</h1> <p>name: {{name}}</p> <p>age: {{age}}</p> <p>job: {{job.type}}</p> <p>salary: {{job.salary}}</p> <button @click="changeInfo">修改信息</button> </template> <script> import {ref} from vue export default { name: App, setup() { // 数据 let name = ref(ZS) let age = ref(22) let job = ref({ type: 前端工程师, salary: 30k }) // 方法 function changeInfo() { name.value = LS age.value = 30 job.value.type = Java开发工程师 job.value.salary = 40k } // 返回一个对象 return { name, age, job, changeInfo } } } </script>

🥽 reactive函数

作用: 定义一个对象类型的响应式数据(基本类型不要用它        ,要用ref函数) 语法:const 代理对象= reactive(源对象)接收一个对象(或数组)       ,返回一个代理对象(Proxy的实例对象                     ,简称proxy对象) reactive定义的响应式数据是“深层次的              ”              。 内部基于 ES6 的 Proxy 实现               ,通过代理对象操作源对象内部数据进行操作                     。 <template> <h1>个人信息</h1> <p>name: {{name}}</p> <p>age: {{age}}</p> <p>job: {{job.type}}</p> <p>salary: {{job.salary}}</p> <p>hobby: {{hobby}}</p> <p>测试数据:{{job.a.b.c}}</p> <button @click="changeInfo">修改信息</button> </template> <script> import {ref, reactive} from vue export default { name: App, setup() { // 数据 let name = ref(ZS) let age = ref(22) let job = reactive({ type: 前端工程师, salary: 30k, a: { b: { c: 1000 } } }) let hobby = reactive([football, basketball]) // 方法 function changeInfo() { name.value = LS age.value = 30 job.type = Java开发工程师 job.salary = 40k job.a.b.c = 2000 hobby[0] = reading } // 返回一个对象 return { name, age, job, hobby, changeInfo } } } </script>

🥽Vue3.0中的响应式原理

🌊 vue2.x的响应式

实现原理:

对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)        。

数组类型:通过重写更新数组的一系列方法来实现拦截       。(对数组的变更方法进行了包裹)                     。

Object.defineProperty(data, count, { get () {}, set () {} })

存在问题:

新增属性                     、删除属性, 界面不会更新               。 使用this.$set(对象, 新属性名, 新属性值)或Vue.set(对象, 新属性名, 新属性值)新增属性       ,使用this.$delete(对象, 属性名)或Vue.$delete(对象, 属性名)删除属性       。 直接通过下标修改数组, 界面不会自动更新                     。 使用this.$set(数组, 数组下标, ‘新值’)或数组.splice(下标, 下标+1, ‘新值’)实现修改数组元素值               。

🌊 Vue3.0的响应式

在Vue3中不存在“新增属性                      、删除属性, 界面不会更新                      ”与“直接通过下标修改数组, 界面不会自动更新       ”的问题。

<template> <h1>个人信息</h1> <p v-show="person.name">name: {{person.name}}</p> <p>age: {{person.age}}</p> <p v-show="person.sex">sex: {{person.sex}}</p> <p>hobby: {{person.hobby}}</p> <button @click="changeInfo">changeInfo</button> <button @click="addSex">addSex</button> <button @click="deleteName">deleteName</button> </template> <script> import {ref, reactive} from vue export default { name: App, setup() { // 数据 const person = reactive({ name: ZS, age: 22, hobby: [apple, orange] }) // 方法 function changeInfo() { person.hobby[0] = mango } function addSex() { person.sex = male } function deleteName() { delete person.name } // 返回一个对象 return { person, changeInfo, addSex, deleteName, } } } </script>

实现原理:

通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加              、属性的删除等                     。

//源数据 let person = { name:张三, age:18 } //模拟Vue3中实现响应式 //Proxy对属性的增删改查都可以监测得到 //#region const p = new Proxy(person,{ //有人读取p的某个属性时调用 get(target,propName){ console.log(`有人读取了p身上的${propName}属性`) return target[propName] }, //有人修改p的某个属性                      、或给p追加某个属性时调用 set(target,propName,value){ console.log(`有人修改了p身上的${propName}属性                     ,我要去更新界面了!`) target[propName] = value }, //有人删除p的某个属性时调用 deleteProperty(target,propName){ console.log(`有人删除了p身上的${propName}属性               ,我要去更新界面了!`) return delete target[propName] } }) //#endregion

通过Reflect(反射): 对源对象的属性进行操作                      。

// Reflect(反射) // 读取对象指定属性的值 Reflect.get(object, 属性名) // 修改对象指定属性的值 Reflect.set(object, 属性名, 新属性值) // 删除对象指定属性 Reflect.deleteProperty(object, 属性名) //模拟Vue3中实现响应式 //#region const p = new Proxy(person,{ //有人读取p的某个属性时调用 get(target,propName){ console.log(`有人读取了p身上的${propName}属性`) return Reflect.get(target,propName) }, //有人修改p的某个属性        、或给p追加某个属性时调用 set(target,propName,value){ console.log(`有人修改了p身上的${propName}属性,我要去更新界面了!`) Reflect.set(target,propName,value) }, //有人删除p的某个属性时调用 deleteProperty(target,propName){ console.log(`有人删除了p身上的${propName}属性                     ,我要去更新界面了!`) return Reflect.deleteProperty(target,propName) } }) //#endregion

MDN文档中描述的Proxy与Reflect:

Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

new Proxy(data, { // 拦截读取属性值 get (target, prop) { return Reflect.get(target, prop) }, // 拦截设置属性值或添加新属性 set (target, prop, value) { return Reflect.set(target, prop, value) }, // 拦截删除属性 deleteProperty (target, prop) { return Reflect.deleteProperty(target, prop) } }) proxy.name = tom

🥽 reactive对比ref

从定义数据角度对比: ref用来定义:基本类型数据。 reactive用来定义:对象(或数组)类型数据              。 备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象                      。 从原理角度对比: ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)        。 reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据              。 从使用角度对比: ref定义的数据:操作数据需要.value                      ,读取数据时模板中直接读取不需要.value                     。 reactive定义的数据:操作数据与读取数据:均不需要.value        。 一般将数据封装在一个data对象中,利用reactive函数将该对象变为响应式数据对象

🥽 setup的两个注意点

setup执行的时机 在beforeCreate之前执行一次              ,this是undefined                      ,在setup无法使用this       。 setup的参数 props:值为对象        ,包含:组件外部传递过来              ,且组件内部声明接收了的属性                     。 context:上下文对象 attrs: 值为对象                     ,包含:组件外部传递过来        ,但没有在props配置中声明接收的属性, 相当于 this.$attrs               。存放没有被组件props配置项接收的数据       ,如果组件外部传递过来的数据都被组件props配置项接收                     ,则该对象为空       。 slots: 收到的插槽内容, 相当于 this.$slots                     。Vue3中具名插槽使用v-slot:插槽名 emit: 分发自定义事件的函数, 相当于 this.$emit               。Vue3绑定的自定义事件在组件中需要使用emits配置项接收。

App.vue

<template> <Demo @hello="showHelloMsg" msg="你好啊" school="尚硅谷"> <!-- Vue3中具名插槽使用 `v-slot:插槽名` --> <template v-slot:qwe> <span>尚硅谷</span> </template> <template v-slot:asd> <span>尚硅谷</span> </template> </Demo> </template> <script> import Demo from ./components/Demo export default { name: App, components:{Demo}, setup(){ // 自定义事件的处理函数 function showHelloMsg(value){ alert(`你好啊               ,你触发了hello事件       ,我收到的参数是:${value}!`) } return { showHelloMsg } } } </script>

Demo.vue

<template> <h1>一个人的信息</h1> <h2>姓名:{{person.name}}</h2> <h2>年龄:{{person.age}}</h2> <button @click="test">测试触发一下Demo组件的Hello事件</button> </template> <script> import {reactive} from vue export default { name: Demo, props:[msg,school], emits:[hello], // 绑定的自定义事件在组件中需要使用emits配置项接收 setup(props,context){ // console.log(---setup---,props) // console.log(---setup---,context) // console.log(---setup---,context.attrs) //相当与Vue2中的$attrs // console.log(---setup---,context.emit) //触发自定义事件的                     。 console.log(---setup---,context.slots) //插槽 //数据 let person = reactive({ name:张三, age:18 }) //方法 function test(){ // 触发自定义事件 context.emit(hello,666) } //返回一个对象(常用) return { person, test } } } </script>

🥽 computed函数

与Vue2.x中computed配置功能一致                     ,在Vue3中可以使用Vue2中的写法(向下兼容)                      。在Vue3中计算属性使用computed函数。

写法

import {computed} from vue setup(){ ... //计算属性——简写 let fullName = computed(()=>{ return person.firstName + - + person.lastName }) //计算属性——完整 let fullName = computed({ get(){ return person.firstName + - + person.lastName }, set(value){ const nameArr = value.split(-) person.firstName = nameArr[0] person.lastName = nameArr[1] } }) } <template> <h1>一个人的信息</h1> 姓: <input type="text" v-model="person.firstName"><br/> 名: <input type="text" v-model="person.lastName"><br/> <p>全名: {{person.fullName}}</p> </template> <script> import {reactive, computed} from vue export default { name: Demo, setup(){ //数据 let person = reactive({ firstName: , lastName: }) // 计算属性 person.fullName = computed(()=>{ return person.firstName + - + person.lastName }) //返回一个对象 return { person, } } } </script>

🥽 watch函数

与Vue2.x中watch配置功能一致               ,在Vue3中可以使用Vue2中的写法(向下兼容)              。

两个小“坑       ”:

监视reactive定义的响应式数据时:oldValue无法正确获取              、强制开启了深度监视(deep配置失效)                      。 监视reactive定义的响应式数据中某个属性时:deep配置有效        。 //数据 let sum = ref(0) let msg = ref(你好啊) let person = reactive({ name:张三, age:18, job:{ j1:{ salary:20 } } }) //情况一:监视ref定义的响应式数据 // 第一个参数为监视的数据,第二个参数为回调函数                     ,第三个参数为配置属性 watch(sum,(newValue,oldValue)=>{ console.log(sum变化了,newValue,oldValue) },{immediate:true}) //情况二:监视多个ref定义的响应式数据 // newValue,oldValue为数组类型数据 watch([sum,msg],(newValue,oldValue)=>{ console.log(sum或msg变化了,newValue,oldValue) }) /* 情况三:监视reactive定义的响应式数据 若watch监视的是reactive定义的响应式数据                      ,则无法正确获得oldValue!! 如果需要获取监视对象中某个属性的oldValue,可以采用将该属性单独取出使用ref的形式 若watch监视的是reactive定义的响应式数据              ,则强制开启了深度监视 */ // 如果监视的对象为使用ref函数实现响应式                      ,则需要监视`变量.value`        ,对于对象类型数据ref借助了reactive watch(person,(newValue,oldValue)=>{ console.log(person变化了,newValue,oldValue) },{immediate:true,deep:false}) //此处的deep配置不再奏效 //情况四:监视reactive定义的响应式数据中的某个属性 watch(()=>person.job,(newValue,oldValue)=>{ console.log(person的job变化了,newValue,oldValue) },{immediate:true,deep:true}) //情况五:监视reactive定义的响应式数据中的某些属性 watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{ console.log(person的job变化了,newValue,oldValue) },{immediate:true,deep:true}) //特殊情况 // 监视reactive所定义的对象中的某个属性              ,且该属性也为对象类型 watch(()=>person.job,(newValue,oldValue)=>{ console.log(person的job变化了,newValue,oldValue) },{deep:true}) //此处由于监视的是reactive所定义的对象中的某个属性                     ,所以deep配置有效 对于使用ref函数定义的数据        ,如果为基本数据类型       ,则使用watch监视时                     ,不使用变量.value的形式               ,因为不能监视一个字面量       ,监视的需要为一个存放数据的结构;如果为对象类型                     ,此时value的值为Proxy对象               ,如果没有开启深度监视,只要value对应的对象的引用没有改变相当于值没有修改                     ,解决方法: 开启深度监视                      ,监视Proxy对象中属性的变化 监视变量.value,由于Proxy对象时ref函数借助reactive函数生成的              ,监视变量.value相当于监视reactive函数生成的Proxy对象

🥽 watchEffect函数

watch的套路是:既要指明监视的属性                      ,也要指明监视的回调              。 watchEffect的套路是:不用指明监视哪个属性        ,监视的回调中用到哪个属性              ,那就监视哪个属性                     。 watchEffect有点像computed: 两个函数中所依赖的数据发生变化                     ,都会重新执行一次回调        。 但computed注重的计算出来的值(回调函数的返回值)        ,所以必须要写返回值       。 而watchEffect更注重的是过程(回调函数的函数体)       ,所以不用写返回值                     。 //watchEffect所指定的回调中用到的数据只要发生变化                     ,则直接重新执行回调               。 watchEffect(()=>{ const x1 = sum.value const x2 = person.age console.log(watchEffect配置的回调执行了) })

🥽 生命周期

Vue3.0中可以继续使用Vue2.x中的生命周期钩子               ,但有有两个被更名:

beforeDestroy改名为 beforeUnmount

destroyed改名为 unmounted

App.vue

<template> <button @click="isShowDemo = !isShowDemo">切换隐藏/显示</button> <Demo v-if="isShowDemo"/> </template> <script> import {ref} from vue import Demo from ./components/Demo export default { name: App, components:{Demo}, setup() { let isShowDemo = ref(true) return {isShowDemo} } } </script>

Demo.vue

<template> <h2>当前求和为:{{sum}}</h2> <button @click="sum++">点我+1</button> </template> <script> import { ref } from vue export default { name: Demo, setup() { //数据 let sum = ref(0) //返回一个对象(常用) return { sum } }, //通过配置项的形式使用生命周期钩子 //#region 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---) } //#endregion } </script>

Vue3.0也提供了 Composition API 形式的生命周期钩子       ,与Vue2.x中钩子对应关系如下:

beforeCreate===>setup()

created=======>setup()

beforeCreate与created没有对应组合式API                     ,setup()相当于beforeCreate与created               ,对于配置项setup()的执行时机早于配置项beforeCreate与created       。

beforeMount ===>onBeforeMount

mounted=======>onMounted

beforeUpdate===>onBeforeUpdate

updated =======>onUpdated

beforeUnmount ==>onBeforeUnmount

unmounted =====>onUnmounted

如果组合式API的生命周期与配置项形式的生命周期一起写,组合式API的生命周期的执行时机优先于配置项形式的生命周期                     。

一般情况下统一使用组合式API的生命周期                     ,或者统一使用配置项形式的生命周期

<template> <h2>当前求和为:{{sum}}</h2> <button @click="sum++">点我+1</button> </template> <script> import {ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from vue export default { name: Demo, setup(){ console.log(---setup---) //数据 let sum = ref(0) //通过组合式API的形式去使用生命周期钩子 onBeforeMount(()=>{ console.log(---onBeforeMount---) }) onMounted(()=>{ console.log(---onMounted---) }) onBeforeUpdate(()=>{ console.log(---onBeforeUpdate---) }) onUpdated(()=>{ console.log(---onUpdated---) }) onBeforeUnmount(()=>{ console.log(---onBeforeUnmount---) }) onUnmounted(()=>{ console.log(---onUnmounted---) }) //返回一个对象(常用) return {sum} }, //通过配置项的形式使用生命周期钩子 //#region 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---) }, //#endregion } </script>

🥽 自定义hook函数

什么是hook?—— 本质是一个函数                      ,把setup函数中使用的Composition API进行了封装               。

类似于vue2.x中的mixin。

自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂                     。

src\hooks\usePoint.js

import {reactive,onMounted,onBeforeUnmount} from vue export default function() { //实现鼠标“打点                      ”相关的数据 let point = reactive({ x:0, y:0 }) //实现鼠标“打点              ”相关的方法 function savePoint(event){ point.x = event.pageX point.y = event.pageY console.log(event.pageX,event.pageY) } //实现鼠标“打点       ”相关的生命周期钩子 onMounted(()=>{ window.addEventListener(click,savePoint) }) onBeforeUnmount(()=>{ window.removeEventListener(click,savePoint) }) return point }

Demo.vue

<template> <h2>当前求和为:{{sum}}</h2> <button @click="sum++">点我+1</button> <hr> <h2>当前点击时鼠标的坐标为:x:{{point.x}},y:{{point.y}}</h2> </template> <script> import {ref} from vue import usePoint from ../hooks/usePoint export default { name: Demo, setup(){ //数据 let sum = ref(0) let point = usePoint() //返回一个对象(常用) return {sum,point} } } </script>

🥽 toRef

作用:创建一个 ref 对象              ,其value值指向另一个对象中的某个属性                      。 语法:const name = toRef(person,name) 应用: 要将响应式对象中的某个属性单独提供给外部使用时。 扩展:toRefs与toRef功能一致                      ,但可以批量创建多个 ref 对象        ,创建一个对象中所有属性对应的 ref 对象              ,语法:toRefs(person) <template> <h4>{{person}}</h4> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> <h2>薪资:{{job.j1.salary}}K</h2> <button @click="name+=~">修改姓名</button> <button @click="age++">增长年龄</button> <button @click="job.j1.salary++">涨薪</button> </template> <script> import {ref,reactive,toRef,toRefs} from vue export default { name: Demo, setup(){ //数据 let person = reactive({ name:张三, age:18, job:{ j1:{ salary:20 } } }) // const name1 = person.name // console.log(%%%,name1) // const name2 = toRef(person,name) // console.log(####,name2) const x = toRefs(person) console.log(******,x) //返回一个对象(常用) return { person, // name:toRef(person,name), // age:toRef(person,age), // salary:toRef(person.job.j1,salary), ...toRefs(person) } } } </script>

🥽 shallowReactive 与 shallowRef

shallowReactive:只处理对象最外层属性的响应式(浅响应式)              。 shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理                     ,对于对象类型数据直接将该对象作为ref对象的value的值                      。 什么时候使用? 如果有一个对象数据        ,结构比较深, 但变化时只是最外层属性变化 ===> shallowReactive        。 如果有一个对象数据       ,后续功能不会修改该对象中的属性                     ,而是生成新的对象来替换               ,即对于该对象数据在后续功能中不会修改其属性       ,而是会将该对象整个进行替换 ===> shallowRef              。

🥽 readonly 与 shallowReadonly

readonly 与 shallowReadonly 均接收一个响应式数据为参数                     。 readonly: 让一个响应式数据变为只读的(深只读)                     ,传入的响应式数据不管有几层               ,都不能进行修改        。 shallowReadonly:让一个响应式数据变为只读的(浅只读),传入的响应式数据只有最外层数据不能进行修改       。 应用场景: 不希望数据被修改时                     。将数据交给其他组件并且不希望这个组件对数据进行更改               。

🥽 toRaw 与 markRaw

toRaw: toRaw 接收一个响应式对象为参数                     ,只能接收reactive生成的响应式对象                      ,不能处理ref生成的响应式数据 作用:将一个由reactive生成的响应式对象转为普通对象       。 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作              ,不会引起页面更新                     。 markRaw: 接收一个对象类型数据为参数 作用:标记一个对象                      ,使其永远不会再成为响应式对象               。向一个已经是响应式对象的数据追加一个属性        ,该属性的值为对象类型数据              ,vue会为其自动添加响应式                     ,当不希望该属性的值为响应式时可以使用该函数        ,减小开销。 应用场景: 有些值不应被设置为响应式的       ,例如复杂的第三方类库等                     ,如果向响应式对象追加一个第三方类库对象(一般属性多且层次多)               ,开销会很大                     。 当渲染具有不可变数据源的大列表时       ,跳过响应式转换可以提高性能                      。

🥽 customRef

作用:创建一个自定义的 ref                     ,并对其依赖项跟踪和更新触发进行显式控制。

实现防抖效果:

<template> <input type="text" v-model="keyword"> <h3>{{keyword}}</h3> </template> <script> import {ref,customRef} from vue export default { name:Demo, setup(){ // let keyword = ref(hello) //使用Vue准备好的内置ref //自定义一个myRef function myRef(value,delay){ let timer //通过customRef去实现自定义 return customRef((track,trigger)=>{ return{ get(){ // 读取数据时调用 track() //告诉Vue这个value值是需要被“追踪                      ”的               ,告诉vue追踪数据的变化 return value }, set(newValue){ // 修改数据时调用 clearTimeout(timer) // 触发就清除原先的定时器不执行之前定时器的回调 timer = setTimeout(()=>{ value = newValue // 修改数据 trigger() //告诉Vue去更新界面,重新解析模板 },delay) } } }) } let keyword = myRef(hello,500) //使用程序员自定义的ref return { keyword } } } </script>

🥽 provide 与 inject

作用:实现祖与后代组件间通信

套路:父组件有一个 provide 选项来提供数据                     ,后代组件有一个 inject 选项来开始使用这些数据

具体写法:

祖组件中:

setup(){ ...... let car = reactive({name:奔驰,price:40万}) // 给后代组件传递数据 // 第一个参数为对传递数据的命名                      ,第二个参数为传递的数据 provide(car,car) ...... }

后代组件中:

setup(props,context){ ...... // 获取祖组件传递过来命名为car的数据 const car = inject(car) return {car} ...... }

🥽 响应式数据的判断

isRef: 检查一个值是否为一个 ref 对象 isReactive: 检查一个对象是否是由 reactive 创建的响应式代理 isReadonly: 检查一个对象是否是由 readonly 创建的只读代理 isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理

🥽 Composition API 的优势

🌊 Options API (配置式API)存在的问题

使用传统OptionsAPI中,新增或者修改一个需求              ,就需要分别在data                      ,methods        ,computed里修改               。同一个需求的数据                     、方法等较分散不集中                      。

🌊 Composition API (组合式API)的优势

我们可以更加优雅的组织我们的代码              ,函数        。让相关功能的代码更加有序的组织在一起              。

🥽 Fragment

在Vue2中: 组件必须有一个根标签

在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中

好处: 减少标签层级, 减小内存占用

🥽 Teleport

什么是Teleport?—— Teleport 是一种能够将我们的组件html结构移动到指定位置的技术                     。

<!-- 移动位置可以标签元素或标签选择器 --> <teleport to="移动位置"> <div v-if="isShow" class="mask"> <div class="dialog"> <h3>我是一个弹窗</h3> <button @click="isShow = false">关闭弹窗</button> </div> </div> </teleport> <template> <div> <button @click="isShow = true">点我弹个窗</button> <!-- 将html结构移动到body中 --> <teleport to="body"> <div v-if="isShow" class="mask"> <div class="dialog"> <h3>我是一个弹窗</h3> <h4>一些内容</h4> <h4>一些内容</h4> <h4>一些内容</h4> <button @click="isShow = false">关闭弹窗</button> </div> </div> </teleport> </div> </template> <script> import {ref} from vue export default { name:Dialog, setup(){ let isShow = ref(false) return {isShow} } } </script> <style> .mask{ position: absolute; top: 0;bottom: 0;left: 0;right: 0; background-color: rgba(0, 0, 0, 0.5); } .dialog{ position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); text-align: center; width: 300px; height: 300px; background-color: green; } </style>

🥽 Suspense

// 静态引入只要组件不引入成功                     ,当前整个组件都不会进行显示 // import Child from ./components/Child//静态引入 // 异步引入引入的组件等加载完成再进行显示        ,当前组件可以不用等待引入成功即可先进行显示 import {defineAsyncComponent} from vue const Child = defineAsyncComponent(()=>imp

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
python-pip-whl(python中pip如何使用) clockology安装不上watch(CLOC Count Lines of Code)