【Vue】Vue3(1)

文章目录

  • 1 Vue3简介
  • 2 Vue3带来了什么
    • 2.1 性能的提升
    • 2.2 源码的升级
    • 2.3 拥抱TypeScript
    • 2.4 新的特性
  • 3 创建Vue3.0工程
    • 3.1 使用 vue-cli 创建
    • 3.2 使用 vite 创建
    • 3.3 main.js
    • 3.4 App.vue
  • 4 常用 Composition API
    • 4.1 拉开序幕的setup
      • 4.1.1 setup函数的两种返回值
      • 4.1.2 注意点
      • 4.1.3 App.vue
    • 4.2 ref函数
      • 4.2.1 App.vue
    • 4.3 reactive函数
      • 4.3.1 App.vue
    • 4.4 Vue3.0中的响应式原理
      • 4.4.1 vue2.x的响应式
      • 4.4.2 Vue3.0的响应式
      • 4.4.3 App.vue
    • 4.5 reactive对比ref
    • 4.6 setup的两个注意点
      • 4.6.1 App.vue
      • 4.6.2 Demo.vue
    • 4.7 计算属性与监视
      • 4.7.1 computed函数
        • 4.7.1.1 Demo.vue
      • 4.7.2 watch函数
        • 4.7.2.1 Demo.vue
      • 4.7.3 watch监视ref数据的说明
      • 4.7.4 watchEffect函数
        • 4.7.4.1 Demo.vue
    • 4.8 生命周期
      • 4.8.1 APP.vue
      • 4.8.2 Demo.vue
    • 4.9 自定义hook函数
      • 4.9.1 hooks文件夹下:usePoint.js
      • 4.9.2 Demo.vue
      • 4.9.3 Test.vue
    • 4.10 toRef
      • 4.10.1 Demo.vue

1 Vue3简介

  • 2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)。
  • 耗时2年多、2600+次提交、30+个RFC、600+次PR、99位贡献者 。
  • github上的tags地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.0。

2 Vue3带来了什么

2.1 性能的提升

  • 打包大小减少41%。

  • 初次渲染快55%, 更新渲染快133%。

  • 内存减少54%。

2.2 源码的升级

  • 使用Proxy代替defineProperty实现响应式。

  • 重写虚拟DOM的实现和Tree-Shaking。

2.3 拥抱TypeScript

  • Vue3可以更好的支持TypeScript。

2.4 新的特性

  • Composition API(组合API)

    • setup配置
    • ref与reactive
    • watch与watchEffect
    • provide与inject
  • 新的内置组件

    • Fragment
    • Teleport
    • Suspense
  • 其他改变

    • 新的生命周期钩子
    • data 选项应始终被声明为一个函数
    • 移除keyCode支持作为 v-on 的修饰符

3 创建Vue3.0工程

3.1 使用 vue-cli 创建

官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create。

## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version
## 安装或者升级你的@vue/cli
npm install -g @vue/cli
## 创建
vue create vue_test
## 启动
cd vue_test
npm run serve

3.2 使用 vite 创建

官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite。

vite官网:https://vitejs.cn。

  • 什么是vite?—— 新一代前端构建工具。
  • 优势如下:
    • 开发环境中,无需打包操作,可快速的冷启动。
    • 轻量快速的热重载(HMR)。
    • 真正的按需编译,不再等待整个应用编译完成。
## 创建工程
npm init vite-app <project-name>
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev

3.3 main.js

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

3.4 App.vue

<template><!-- Vue3组件中的模板结构可以没有根标签 --><img alt="Vue logo" src="./assets/logo.png"><HelloWorld msg="Welcome to Your Vue.js App"/>
</template><script>import HelloWorld from './components/HelloWorld.vue'export default {name: 'App',components: {HelloWorld}}
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;
}
</style>

4 常用 Composition API

官方文档:https://v3.cn.vuejs.org/guide/composition-api-introduction.html。

4.1 拉开序幕的setup

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

4.1.1 setup函数的两种返回值

  • 若返回一个对象,则对象中的属性、方法,在模板中均可以直接使用。(重点关注!)
  • 若返回一个渲染函数:则可以自定义渲染内容。(了解)

4.1.2 注意点

  • 尽量不要与Vue2.x配置混用
    • Vue2.x配置(data、methos、computed…)中可以访问到setup中的属性、方法。
    • 但在setup中不能访问到Vue2.x配置(data、methos、computed…)。
    • 如果有重名,setup优先。
  • setup不能是一个async函数,因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)

4.1.3 App.vue

<template><h1>一个人的信息</h1><h2>姓名:{{name}}</h2><h2>年龄:{{age}}</h2><h2>性别:{{sex}}</h2><h2>a的值是:{{a}}</h2><button @click="sayHello">说话(Vue3所配置的——sayHello)</button><br><br><button @click="sayWelcome">说话(Vue2所配置的——sayWelcome)</button><br><br><button @click="test1">测试一下在Vue2的配置中去读取Vue3中的数据、方法</button><br><br><button @click="test2">测试一下在Vue3的setup配置中去读取Vue2中的数据、方法</button></template><script>// import {h} from 'vue'export default {name: 'App',data() {return {sex:'男',a:100}},methods: {sayWelcome(){alert('欢迎来到尚硅谷学习')},test1(){console.log(this.sex)console.log(this.name)console.log(this.age)console.log(this.sayHello)}},//此处只是测试一下setup,暂时不考虑响应式的问题。async setup(){//数据let name = '张三'let age = 18let a = 200//方法function sayHello(){alert(`我叫${name},我${age}岁了,你好啊!`)}function test2(){console.log(name)console.log(age)console.log(sayHello)console.log(this.sex)console.log(this.sayWelcome)}//返回一个对象(常用)return {name,age,sayHello,test2,a}//返回一个函数(渲染函数)// return ()=> h('h1','尚硅谷')}}
</script>

4.2 ref函数

  • 作用:定义一个响应式的数据。
  • 语法:const xxx = ref(initValue)
    • 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)
    • JS中操作数据: xxx.value
    • 模板中读取数据:不需要.value,直接:<div>{{xxx}}</div>
  • 备注:
    • 接收的数据可以是:基本类型、也可以是对象类型。
    • 基本类型的数据:响应式依然是靠Object.defineProperty()getset完成的。
    • 对象类型的数据:内部 “ 求助 ”了Vue3.0中的一个新函数—— reactive函数。

4.2.1 App.vue

<template><h1>一个人的信息</h1><h2>姓名:{{name}}</h2><h2>年龄:{{age}}</h2><h3>工作种类:{{job.type}}</h3><h3>工作薪水:{{job.salary}}</h3><button @click="changeInfo">修改人的信息</button>
</template><script>import {ref} from 'vue'export default {name: 'App',setup(){//数据let name = ref('张三')let age = ref(18)let job = ref({type:'前端工程师',salary:'30K'})//方法function changeInfo(){// name.value = '李四'// age.value = 48console.log(job.value)// job.value.type = 'UI设计师'// job.value.salary = '60K'// console.log(name,age)}//返回一个对象(常用)return {name,age,job,changeInfo}}}
</script>

4.3 reactive函数

  • 作用:定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)。
  • 语法:const 代理对象 = reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)
  • reactive定义的响应式数据是“深层次的”。
  • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。

4.3.1 App.vue

<template><h1>一个人的信息</h1><h2>姓名:{{person.name}}</h2><h2>年龄:{{person.age}}</h2><h3>工作种类:{{person.job.type}}</h3><h3>工作薪水:{{person.job.salary}}</h3><h3>爱好:{{person.hobby}}</h3><h3>测试的数据c:{{person.job.a.b.c}}</h3><button @click="changeInfo">修改人的信息</button>
</template><script>import {reactive} from 'vue'export default {name: 'App',setup(){//数据let person = reactive({name:'张三',age:18,job:{type:'前端工程师',salary:'30K',a:{b:{c:666}}},hobby:['抽烟','喝酒','烫头']})//方法function changeInfo(){person.name = '李四'person.age = 48person.job.type = 'UI设计师'person.job.salary = '60K'person.job.a.b.c = 999person.hobby[0] = '学习'}//返回一个对象(常用)return {person,changeInfo}}}
</script>

4.4 Vue3.0中的响应式原理

4.4.1 vue2.x的响应式

  • 实现原理:

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

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

      Object.defineProperty(data, 'count', {get () {}, set () {}
      })
      
  • 存在问题:

    • 新增属性、删除属性,界面不会更新。
    • 直接通过下标修改数组,界面不会自动更新。

4.4.2 Vue3.0的响应式

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

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

    • 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' 
      

4.4.3 App.vue

<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>Document</title></head><body><script type="text/javascript" >//源数据let person = {name:'张三',age:18}//模拟Vue2中实现响应式//#region /* let p = {}Object.defineProperty(p,'name',{configurable:true,get(){ //有人读取name时调用return person.name},set(value){ //有人修改name时调用console.log('有人修改了name属性,我发现了,我要去更新界面!')person.name = value}})Object.defineProperty(p,'age',{get(){ //有人读取age时调用return person.age},set(value){ //有人修改age时调用console.log('有人修改了age属性,我发现了,我要去更新界面!')person.age = value}}) *///#endregion//模拟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)}})//#endregionlet obj = {a:1,b:2}//通过Object.defineProperty去操作//#region /* try {Object.defineProperty(obj,'c',{get(){return 3}})Object.defineProperty(obj,'c',{get(){return 4}})} catch (error) {console.log(error)} *///#endregion//通过Reflect.defineProperty去操作//#region /* const x1 = Reflect.defineProperty(obj,'c',{get(){return 3}})console.log(x1)const x2 = Reflect.defineProperty(obj,'c',{get(){return 4}}) if(x2){console.log('某某某操作成功了!')}else{console.log('某某某操作失败了!')} *///#endregion// console.log('@@@')</script></body>
</html>

4.5 reactive对比ref

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

4.6 setup的两个注意点

  • setup执行的时机
    • 在beforeCreate之前执行一次,this是undefined。
  • setup的参数
    • props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
    • context:上下文对象
      • attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs
      • slots: 收到的插槽内容, 相当于 this.$slots
      • emit: 分发自定义事件的函数, 相当于 this.$emit

4.6.1 App.vue

<template><Demo @hello="showHelloMsg" msg="你好啊" school="尚硅谷"><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>

4.6.2 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'],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>

4.7 计算属性与监视

4.7.1 computed函数

  • 与Vue2.x中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]}})
    }
    
4.7.1.1 Demo.vue
<template><h1>一个人的信息</h1>姓:<input type="text" v-model="person.firstName"><br>名:<input type="text" v-model="person.lastName"><br><span>全名:{{person.fullName}}</span><br>全名:<input type="text" v-model="person.fullName">
</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}) *///计算属性——完整写法(考虑读和写)person.fullName = computed({get(){return person.firstName + '-' + person.lastName},set(value){const nameArr = value.split('-')person.firstName = nameArr[0]person.lastName = nameArr[1]}})//返回一个对象(常用)return {person}}}
</script>

4.7.2 watch函数

  • 与Vue2.x中watch配置功能一致

  • 两个小“坑”:

    • 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
    • 监视reactive定义的响应式数据中某个属性时:deep配置有效。
    //情况一:监视ref定义的响应式数据
    watch(sum,(newValue,oldValue)=>{console.log('sum变化了',newValue,oldValue)
    },{immediate:true})//情况二:监视多个ref定义的响应式数据
    watch([sum,msg],(newValue,oldValue)=>{console.log('sum或msg变化了',newValue,oldValue)
    }) /* 情况三:监视reactive定义的响应式数据若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!若watch监视的是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})//特殊情况
    watch(()=>person.job,(newValue,oldValue)=>{console.log('person的job变化了',newValue,oldValue)
    },{deep:true}) //此处由于监视的是reactive所定义的对象中的某个属性,所以deep配置有效
    
4.7.2.1 Demo.vue
<template><h2>当前求和为:{{sum}}</h2><button @click="sum++">点我+1</button><hr><h2>当前的信息为:{{msg}}</h2><button @click="msg+='!'">修改信息</button><hr><h2>姓名:{{person.name}}</h2><h2>年龄:{{person.age}}</h2><h2>薪资:{{person.job.j1.salary}}K</h2><button @click="person.name+='~'">修改姓名</button><button @click="person.age++">增长年龄</button><button @click="person.job.j1.salary++">涨薪</button>
</template><script>import {ref,reactive,watch} from 'vue'export default {name: 'Demo',setup(){//数据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所定义的多个响应式数据/* watch([sum,msg],(newValue,oldValue)=>{console.log('sum或msg变了',newValue,oldValue)},{immediate:true}) *//* 情况三:监视reactive所定义的一个响应式数据的全部属性1.注意:此处无法正确的获取oldValue2.注意:强制开启了深度监视(deep配置无效)*//* watch(person,(newValue,oldValue)=>{console.log('person变化了',newValue,oldValue)},{deep:false}) //此处的deep配置无效 *///情况四:监视reactive所定义的一个响应式数据中的某个属性/* watch(()=>person.name,(newValue,oldValue)=>{console.log('person的name变化了',newValue,oldValue)})  *///情况五:监视reactive所定义的一个响应式数据中的某些属性/* watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{console.log('person的name或age变化了',newValue,oldValue)})  *///特殊情况/* watch(()=>person.job,(newValue,oldValue)=>{console.log('person的job变化了',newValue,oldValue)},{deep:true}) //此处由于监视的是reactive所定义的对象中的某个属性(是个对象),所以deep配置有效,也无法获取正确的oldvalue *///返回一个对象(常用)return {sum,msg,person}}}
</script>

4.7.3 watch监视ref数据的说明

<template><h2>当前求和为:{{sum}}</h2><button @click="sum++">点我+1</button><hr><h2>当前的信息为:{{msg}}</h2><button @click="msg+='!'">修改信息</button><hr><h2>姓名:{{person.name}}</h2><h2>年龄:{{person.age}}</h2><h2>薪资:{{person.job.j1.salary}}K</h2><button @click="person.name+='~'">修改姓名</button><button @click="person.age++">增长年龄</button><button @click="person.job.j1.salary++">涨薪</button>
</template><script>import {ref,reactive,watch} from 'vue'export default {name: 'Demo',setup(){//数据let sum = ref(0)let msg = ref('你好啊')let person = ref({name:'张三',age:18,job:{j1:{salary:20}}})console.log(person)// sum中存储的是基本数据类型的值,监测ref对象({..., _value:sum}),任何一个属性修改都能监测到,不用.valuewatch(sum,(newValue,oldValue)=>{console.log('sum的值变化了',newValue,oldValue)})// ref对象({..., _value:Proxy}),监测reactive所定义的数据,.value后才能监测里面的变化/*watch(person,(newValue,oldValue)=>{console.log('person的值变化了',newValue,oldValue)})*/watch(person.value,(newValue,oldValue)=>{console.log('person的值变化了',newValue,oldValue)})// 或者不.value,设置深度监视,value中的属性也能监视到watch(person,(newValue,oldValue)=>{console.log('person的值变化了',newValue,oldValue)},{deep:true})//返回一个对象(常用)return {sum,msg,person}}}
</script>

4.7.4 watchEffect函数

  • watch的套路是:既要指明监视的属性,也要指明监视的回调。

  • watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。

  • watchEffect有点像computed:

  • 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。

  • 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。

//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
watchEffect(()=>{const x1 = sum.valueconst x2 = person.ageconsole.log('watchEffect配置的回调执行了')
})
4.7.4.1 Demo.vue
<template><h2>当前求和为:{{sum}}</h2><button @click="sum++">点我+1</button><hr><h2>当前的信息为:{{msg}}</h2><button @click="msg+='!'">修改信息</button><hr><h2>姓名:{{person.name}}</h2><h2>年龄:{{person.age}}</h2><h2>薪资:{{person.job.j1.salary}}K</h2><button @click="person.name+='~'">修改姓名</button><button @click="person.age++">增长年龄</button><button @click="person.job.j1.salary++">涨薪</button>
</template><script>import {ref,reactive,watch,watchEffect} from 'vue'export default {name: 'Demo',setup(){//数据let sum = ref(0)let msg = ref('你好啊')let person = reactive({name:'张三',age:18,job:{j1:{salary:20}}})//监视/* watch(sum,(newValue,oldValue)=>{console.log('sum的值变化了',newValue,oldValue)},{immediate:true}) */// 函数中用到谁监视谁watchEffect(()=>{const x1 = sum.valueconst x2 = person.job.j1.salaryconsole.log('watchEffect所指定的回调执行了')})//返回一个对象(常用)return {sum,msg,person}}}
</script>

4.8 生命周期

  • Vue2生命周期图
  • Vue3声明周期图
  • Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:
    • beforeDestroy改名为beforeUnmount
    • destroyed改名为unmounted
  • Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
    • beforeCreate===>setup()
    • created=======>setup()
    • beforeMount ===>onBeforeMount
    • mounted=======>onMounted
    • beforeUpdate===>onBeforeUpdate
    • updated =======>onUpdated
    • beforeUnmount ==>onBeforeUnmount
    • unmounted =====>onUnmounted

4.8.1 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>

4.8.2 Demo.vue

<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的形式去使用生命周期钩子// beforeCreate和created不放进setup()中,setup()就相当于beforeCreate和createdonBeforeMount(()=>{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>

4.9 自定义hook函数

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

  • 类似于vue2.x中的mixin。

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

4.9.1 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.pageXpoint.y = event.pageYconsole.log(event.pageX,event.pageY)}//实现鼠标“打点”相关的生命周期钩子onMounted(()=>{window.addEventListener('click',savePoint)})onBeforeUnmount(()=>{window.removeEventListener('click',savePoint)})return point
}

4.9.2 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>

4.9.3 Test.vue

<template><h2>我是Test组件</h2><h2>当前点击时鼠标的坐标为:x:{{point.x}},y:{{point.y}}</h2>
</template><script>import usePoint from '../hooks/usePoint'export default {name:'Test',setup(){const point = usePoint()return {point}}}
</script>

4.10 toRef

  • 作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。
  • 语法:const name = toRef(person,'name')
  • 应用:要将响应式对象中的某个属性单独提供给外部使用时。
  • 扩展:toRefstoRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)

4.10.1 Demo.vue

<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) // 只将name、age、job拆出来了,j1和salary并未拆出来}}}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/452285.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python酷玩之旅_数据分析入门(matplotlib)

导览 前言matplotlib入门1. 简介1.1 Pairwise data1.2 Statistical distributions1.3 Gridded data1.4 Irregularly gridded data1.5 3D and volumetric data 2. 实践2.1 安装2.2 示例 结语系列回顾 前言 翻看日历&#xff0c;今年的日子已划到了2024年10月19日&#xff0c;今天…

【Linux-进程间通信】vscode使用通信引入匿名管道引入

一、新系统&#xff0c;新软件 1.新系统 哈喽宝子们&#xff0c;从今以后我们不再使用风靡一时的CentOS系统了&#xff0c;因为CentOS已经不在维护了&#xff0c;各大公司几乎也都从CentOS转入其他操作系统了&#xff1b;我们现在由原来的CentOS系统切换到最新的Ubuntu系统&a…

[LeetCode] 232. 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除并返回元素int peek() 返回队列开头…

嵌入式开发中的 C 语言

目录 一、嵌入式与 C 语言的紧密关系 二、C 语言的特点与优势 &#xff08;二&#xff09;灵活的语法机制与直接访问硬件能力 &#xff08;三&#xff09;高效的运行效率 三、C 语言在嵌入式开发中的应用场景 &#xff08;一&#xff09;编译器与源代码转换 &#xff08;…

使用LSPatch+PlusNE修改手机软件

一、问题概述 国内使用一些软件&#xff0c;即使科学上网&#xff0c;打开都是网络错误&#xff0c;更换节点同样如此。 二、软件下载 通过官网或者正规商店(如Google play)下载并且安装。 是的&#xff0c;先要下载一个无法使用的版本&#xff0c;后续对其进行修改。 三、下…

Vulnhub打靶-matrix-breakout-2-morpheus

基本信息 靶机下载&#xff1a;https://pan.baidu.com/s/1kz6ei5hNomFK44p1QT0xzQ?pwdy5qh 提取码: y5qh 攻击机器&#xff1a;192.168.20.128&#xff08;Windows操作系统&#xff09; 靶机&#xff1a;192.168.20.0/24 目标&#xff1a;获取2个flagroot权限 具体流程 …

【AIGC】ChatGPT与人类理解力的共鸣:人机交互中的心智理论(ToM)探索

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;心智理论(Theory of Mind,ToM)心智理论在心理学与神经科学中的重要性心智理论对理解同理心、道德判断和社交技能的重要性结论 &#x1f4af;乌得勒支大学研究对ChatGPT-4…

深入 C 语言内存管理:优化策略与实践案例

目录 引言 C 语言内存管理机制概览 内存区域划分 内存对齐与填充 内存访问效率 内存管理优化策略 避免内存泄漏 减少内存碎片 优化结构体布局 提高内存访问效率 实践案例 案例一&#xff1a;智能指针实现 案例二&#xff1a;内存池实现 案例三&#xff1a;结构体…

PDT 数据集:首个基于无人机的高精密度树木病虫害目标检测数据集

2024-09-24&#xff0c;由中国山东计算机科学中心、北京大学等机构联合创建了Pests and Diseases Tree&#xff08;PDT&#xff09;数据集&#xff0c;目的解决农业领域中病虫害检测模型开发中专业数据集缺失的问题。通过集成公共数据和网络数据&#xff0c;进一步推出了Common…

MySQL程序介绍<一>

目录 MySQL程序简介 mysqld - MySQL 服务器 ​编辑 mysql - MySQL 命令⾏客⼾端 MySQL程序简介 1.MySQL安装完成通常会包含如下程序&#xff1a; Linux系统程序⼀般在 /usr/bin⽬录下&#xff0c;可以通过命令查看 windows系统⽬录&#xff1a; 你的安装路径\MySQL Server…

【LeetCode】123.买卖股票的最佳时间

清晰明了的思路是解决问题的至上法宝。如何把一个复杂的问题拆成简单的问题&#xff0c;就是我们需要考虑的。 1. 题目 2. 思想 这道题虽然是难题&#xff0c;但是思想比较简单。 题目要求说至多买卖两次&#xff0c;也就是说&#xff0c;也可以买卖一次&#xff0c;这种情况…

MySQL-16.DQL-分页查询

一.DQL-分页查询 -- 分页查询 -- 1. 从 起始索引0 开始查询员工数据&#xff0c;每页展示5条记录 select * from tb_emp limit 0,5; -- 2.查询 第1页 员工数据&#xff0c;每页展示5条记录 select * from tb_emp limit 0,5; -- 3.查询 第2页 员工数据&#xff0c;每页展示5条记…

数据中台业务架构图

数据中台的业务架构是企业实现数据驱动决策和业务创新的关键支撑。它主要由数据源层、数据存储与处理层、数据服务层以及数据应用层组成。 数据源层涵盖了企业内部各个业务系统的数据&#xff0c;如 ERP、CRM 等&#xff0c;以及外部数据来源&#xff0c;如社交媒体、行业数据…

ES-入门-javaApi-文档-新增-删除

新增指定索引的文档数据的代码如下&#xff1a; package com.atgulgu.es.test;import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.http.HttpHost; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexRe…

Java项目-基于springboot框架的校园在线拍卖系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

webstorm 编辑器配置及配置迁移

1.下载地址 WebStorm&#xff1a;JetBrains 出品的 JavaScript 和 TypeScript IDE 其他版本下载地址 2.安装 点击下一步安装&#xff0c;可根据需要是否删除已有版本 注意&#xff1a; 完成安装后需要激活 3.设置快捷键 以下为个人常用可跳过或根据需要设置 如&#xff1a…

汇编实现逆序复制数据

一.实验目的 使其可以将10000H &#xff5e; 1000FH中的8个字&#xff0c;逆序复制到20000H &#xff5e; 2000FH中。 二.实验过程表示 三.部分汇编实现代码 mov ax,1000H ;将1000H放入AX寄存器中 mov ds,ax ;将AX寄存器中的内容放入DS寄存器中&#xff0c;这时候DS中存…

Amesim-代数环问题分析与解决办法

Amesim在仿真建模后&#xff0c;进入Simulation模块后&#xff0c;有时会出现代数环的问题&#xff08;如下图所示&#xff09;。Amesim中的代数环问题出现可能不会影响模型的计算&#xff0c;但是会导致计算速度变得缓慢。 当输入信号直接取决于输出信号&#xff0c;同时输出信…

Vue(4)脚手架Vuex

文章目录 脚手架前言render函数&#xff08;关于不同版本的Vue&#xff09;修改默认配置ref属性props配置mixin混入插件scopedlang总结TodoList案例浏览器的本地存储 Vuex简介1.概念2.使用Vuex 搭建环境Vuex案例基本使用 getters配置项vuex 与 vue 的类比四个map方法的使用范例…

SpringBoot项目启动报错:命令行太长解决

文章目录 SpringBoot项目启动报错&#xff1a;命令行太长解决1. 第一种方法1. 第二种方法1-1 旧版本Idea1-2 新版本Idea 3. 重新启动SpringBoot项目即可解决 SpringBoot项目启动报错&#xff1a;命令行太长解决 报错信息&#xff1a; 1. 第一种方法 1. 第二种方法 找到项目…