从入门到精通:Vue3一篇文章搞定!

从入门到精通:Vue3一篇文章搞定!从入门到精通 Vue3 一篇文章搞定 vue3

大家好,欢迎来到IT知识分享网。

从入门到精通:Vue3一篇文章搞定!

依旧青山,本期给大家带来vue篇专栏内容:从入门到精通:Vue3一篇文章搞定!

目录

vue3语法

1、vue3初识

1、vue3简介

2、vue3特点:

3、创建vue3 工程项目

4、vue3目录结构分析

2、Composition API

1、setup函数

2、setup执行时间

3、ref 响应式函数

1、引言:

2、ref 函数

4、reactive 函数

5、vue3响应式原理

1、vue2.x的响应式原理

2、vue3响应式原理

6、Reactive 与 ref 对比

7、vue3中的组件传参

1、父传子

2、子传父

8、vue3中的计算属性

9、vue3 中的 watch监听器

10、vue3生命周期

11、vue3中自定义hook函数

12、toRef 与 toRefs

13、vue3 中的路由

14、vue3 中的vuex

vue3语法

1、vue3初识

1、vue3简介

2020.9 vue.js 发布3版本。 耗时2年多开发完毕。由尤雨溪团队打造。

2、vue3特点:

1、性能提升

  • 打包大小减少41%
  • 初次渲染快51%,更新渲染快133%
  • 内存占用减少54%

2、源码升级

  • 使用Proxy 代替Object.defineProperty 实现双向数据绑定
  • 重写虚拟DOM的实现和Tree-Shaking
  • vue3 更好的支持typescript

3、新的特性

composition API(组合式api)

  • setup配置
  • ref和reactive
  • watch 和watchEffect
  • provide和inject

    提供了新的内置组件

  • Fragment
  • Teleport
  • Suspense

其他改变

  • 新的生命周期钩子
  • 移除keyCode 作为v-on的修饰符

3、创建vue3 工程项目

// 1. 确保你的vue-cli 脚手架版本在4.5.0以上,这样才能创建 // 2. 检查脚手架版本  vue -V 或 vue --version // 3. 如果版本低话,重新安装vue-cli   npm install -g @vue/cli   // 4. vue create vue3-project // 5. cd vue3-project // 6. npm run serve 启动项目 

vite模板搭建vue3项目

npm init vue@latest 

从入门到精通:Vue3一篇文章搞定!

4、vue3目录结构分析

// vue3 入口文件 main.js // 引入的不是Vue构造函数了,而是createApp 这个工厂函数(工厂函数就是返回值为一个对象的函数) import { createApp } from 'vue'   import App from './App.vue'   const app = createApp(App).mount('#app') // app 相当于vue2中的vm,但是比vm轻,里面绑定的属性和方法更少,而不是像vm那样用的不用的都绑上,显的有点重 // vue2入口文件 main.js import Vue from 'vue' import App from './App.vue' const vm = new Vue({   render: h => h(App), }).$mount('#app') // 比较  // vue3 引入的是createApp 这个函数,而不是vue2中的的 Vue 构造函数啦。 // vue3中的 app 类似于之前vue2中的vm, 但是app应用实例对象比vm 更轻,里面绑定的属性和方法更少 
  • 打开app.vue,发现vue3模板结构可以不使用根标签。
<template> <img alt="Vue logo" src="./assets/logo.png"> <HelloWorld msg="Welcome to Your Vue.js App"/> </template> 

2、Composition API

Composition API 也叫组合式api 主要包括如下及部分:

1、setup函数

  • 它是vue3新增的一个配置项,值为一个函数,所有的组合式API 方法都写在在setup函数中。
  • 组件中用到的数据,方法 计算属性,事件方法,监听函数,都配置在setup 中。
  • setup的函数值为一个函数,该函数的返回值为一个对象,对象中的属性和方法均可以在模板中直接使用。代码如下:
<template> <div> <p>姓名:{ 
  { name }}</p> <p>年龄:{ 
  { age }}</p> <p @click="sayHello(10)">说话</p> </div> </template> <script> export default { name: "App", setup() { //为一个函数 //定义变量 let name = "张三"; let age = 20; // 定义方法 function sayHello(m) { alert(`${name}--${age}--${m}`); } return { //setup函数返回值为一个对象 name, age, sayHello, }; }, }; </script> 
  • 注意:setup 函数尽量不要和vue2.x混合使用
    • vue2.x中的(data,methods,computed)可以访问到 setup中的属性和方法
    • 在setup中不能访问vue2.x中的配置数据和方法如(data,methods,computed)

      代码如下:

    <template> <div> <p>姓名:{ 
        { name }}</p> <p>年龄:{ 
        { age }}</p> <p @click="sayHello(10)">说话</p> <p>{ 
        { height }}</p> </div> <!-- vue2.x中的事件 --> <div @click="test1">vue2中的事件test1</div> <!-- vue3中的事件 --> <div @click="test2">vue3中的事件test2</div> </template> <script> export default { name: "App", data() { return { sex: "男", // vue2中的变量 height: 186, // vue2中的变量 }; }, methods: { test1() { console.log(this.name); // "张三" console.log(this.age); // 20; console.log(this.sayHello); // 函数 console.log(this.sex); // 男 }, }, setup() { let name = "张三"; let age = 20; let height = 176; // setup中的变量 function sayHello(m) { alert(`${name}--${age}--${m}`); } function test2() { console.log(this.name); // "张三 console.log(this.sayHello); // 函数 console.log(this.sex); // undefined vue3中的setup 访问不了vue2中数据 console.log(this.test1);// undefined vue3中的setup 访问不了vue2中方法 } return { name, age, sayHello, test2, height,// setup中的变量 }; }, }; 

2、setup执行时间

1、 setup 在beforeCreate之前执行,且setup中获取不到this this为undefined

 beforeCreate() {     console.log("beforeCreate");     console.log(this); // proxy 实例对象   },   setup() {     console.log("setup");     console.log(this); // undefined   } 

3、ref 响应式函数

1、引言:

如下代码:当点击执行changeFn函数,修改setup中定义的变量时,发现页面中的name和age的数据并没有修改,说明该数据不是响应式数据

<template>   <div>111</div>   <p>{ 
  { name }}--{ 
  { age }}</p>   <button @click="changeFn">changeFn</button> </template> <script> export default {   name: "App",   setup() {     //定义变量     let name = "张三";     let age = 20;     // 定义方法     function changeFn() {       name = "李四";       age = 30;     }     return {       //setup函数返回值为一个对象       name,       age,       changeFn,     };   }, }; </script> 

2、ref 函数

  • 它是 vue3中的一个函数,一般用于将基本类型数据处理成响应式数据。
  • 作用:定义一个基本类型的响应式的数据,只有数据成为响应式数据,这样当数据变化时,才能被监测到。
  • 使用时需要从vue中引入
    <script>    import { ref } from "vue"; // 引入响应式函数ref    ... </script> 
  • 语法:const xxx =ref(数据变量);结果 返回一个 RefImpl 的引用对象,获取时为 xxx.value
  • 在页面模板中使用数据直接 使用插值表达式,不需要加value

    姓名:{
    { name }}

    ,因为vue3会自动帮你.value,所以可以拿到值

  • ref 函数实现数据响应式的原理还是利用了vue2的Object.defineProperty() 给数据设置 get set 监听函数,如下图:

    image-20211130230403826

    image-

  • 接收的数据类型可以是基本类型(实现响应式原理为Object.defineProperty()),也可以是对象类型(当为对象时,实现响应式的原理就是Proxy不是Object.defineProperty())

点击如下change事件,修改name 和age

<template> <div> <!--name这个ref 引用对象在使用时不需要加value,vue3会自动帮你加value,所以可以拿到值--> <p>{ 
  { name }}--{ 
  { age }}</p> <p>{ 
  { job.type }}--{ 
  {job.salary}}</p> <p @click="change">说话</p> </div> </template> <script> import { ref } from "vue"; // 引入响应式函数ref export default { name: "App", setup() { let name = ref("张三"); //返回一个 ref 引用对象 let age = ref(20); console.log(name) // 当ref传的参数为对象时 let job = ref({ type: "前端工程师", salary: "20k", }); function change() { name.value = "李四"; // ref对象.value 修改其值 age.value = 30; job.value.type = "后端开发工程师"; job.value.salary = "30k"; } return { name, age, change, job }; }, }; </script> 

4、reactive 函数

1、定义一个对象类型的响应式数据,返回一个Proxy 实例对象,不能用于基本数据类型,否则报错。(基本类型响应式数据使用ref)。

语法:const 代理对象= reactive(源对象) ,接收一个对象或数组,返回一个代理对象(即Proxy源对象

  • 使用时先从vue中引入
<script> import { reactive } from "vue"; ... </script> 
  • 代码如下:
<template>   <p>{ 
  { job.type }} --{ 
  { job.salary }}--{ 
  { job.like.a.b }}--{ 
  {job.content}}</p>   <p v-for="(item, index) in foodArr" :key="index">{ 
  { item }}</p>   <button @click="changeFn">changeFn</button> </template> <script> import { reactive } from "vue"; export default {   name: "App",   components: {},   setup() {     //定义对象     let job = reactive({       type: "前端工程师",       salary: "20k",       like:{           a:{               b:'不告诉你'           }       }     });     console.log(job);     //定义数组     let foodArr = reactive(["刷抖音", "敲代码"]);     console.log(foodArr);     // 定义方法     function changeFn() {       job.type = "后端开发工程师";       job.salary = "30k";       job.content = "写代码"; // 给对象添加属性       foodArr[0]='买包包' // 通过下标修改数组     }     return {       //setup函数返回值为一个对象       job,       changeFn,       foodArr     };   }, }; </script> 
  • vue3中使用proxy 实现的数据响应去掉了vue2中不能检测到对象添加属性和通过下标修改数组而无法检测的情况。

5、vue3响应式原理

1、vue2.x的响应式原理

  • 实现原理:

    通过Object.defineProperty()对属性的读取,修改进行拦截。(也叫数据劫持)即对数据的操作进行监听

       let data = {         name: "张三",         age: 30     }     let p = {}      Object.defineProperty(p, 'name', {             get() {             console.log('访问了name属性');             return data.name         },         set(val) {             console.log('设置name属性');             data.name = val         }     }) //如上存在2个问题: // 无法添加和删除属性 // 无法捕获到修改数组下标改变对应数组 
  • vue2.x存在的问题
    • 对象数据新增属性和删除属性,界面不会响应更新
    <template> <div id="app"> <p>{ 
        { person.name }}</p> <p>{ 
        { person.age }}</p> <p v-if="person.sex">{ 
        { person.sex }}</p> <button @click="addSex">添加属性</button> <button @click="deleteAge">删除属性</button> </div> </template> <script> import Vue from "vue"; export default { name: "App", data() { return { person: { name: "张三", age: 20, }, }; }, components: {}, methods: { addSex() { // this.person.sex = "男"; // console.log(this.person); // 数据被修改,但是vue监测不到 // this.$set(this.person, "sex", "男"); // 修改为第一种方式,vue可以检测到 Vue.set(this.person, "sex", "男"); // 修改为第二种方式,vue也可以检测到 console.log(this.person); }, deleteAge() { // delete this.person.age; // age被删除改,但是vue监测不到 this.$delete(this.person, "age"); // 修改为第一种方式,vue可以检测到 Vue.delete(this.person, "age"); // 修改为第二种方式,vue可以检测到 console.log(this.person); }, }, }; </script> 
    • 数组数据直接通过修改下标,界面不会响应更新
     <div id="app"> <p v-for="(item, index) in nameArr" :key="index">{ 
        { item }}</p> <button @click="update">添加属性</button> </div> <script> import Vue from "vue"; export default { name: "App", data() { return { nameArr: ["刘备", "关羽"], }; }, methods: { update() { // this.nameArr[0] = "张飞"; // 数据被修改了,但是vue 检测不到 // this.nameArr.splice(0, 1, "张飞"); // 修改为第一种方式,数据可以被检测到 // this.$set(this.nameArr, 0, "张飞"); // 修改为第二种方式,数据可以被检测到 Vue.set(this.nameArr, 0, "张飞"); // 修改为第三种方式,数据可以被检测到 console.log(this.nameArr); }, }, }; </script> 

2、vue3响应式原理

1、首先看一下vue3是否还存在vue2.x 中的问题。

  • 对象数据新增属性和删除属性,不存在vue2.x 中的问题了。
<template> <div> <p>{ 
  { person.name }}</p> <p>{ 
  { person.age }}</p> <p>{ 
  { person.sex }}</p> <button @click="addSex">添加属性</button> <button @click="deleteSex">删除属性</button> </div> </template> <script> import { reactive } from "vue"; export default { name: "App", components: {}, setup() { let person = reactive({ name: "张三", age: 20, }); console.log(person); //定义添加属性 function addSex() { person.sex = "男"; console.log(person); } // 定义删除属性 function deleteSex() { delete person.sex; console.log(person); } return { person, addSex, deleteSex, }; }, }; </script> 
  • 数组数据直接通过修改下标,修改数组,不存在vue2.x 中的问题了。
<template> <div> <p v-for="(item, index) in person.like" :key="index">{ 
  { item }}</p> <button @click="change">修改数组的值</button> </div> </template> <script> import { reactive } from "vue"; export default { name: "App", components: {}, setup() { let person = reactive({ name: "张三", age: 20, like: ["打球", "敲代码"], }); console.log(person); // proxy 实例对象 function change() { person.like[0] = "打台球"; } return { person, change, }; }, }; </script> 

2、vue3响应式原理

首先说一下Reflect的作用。

// Reflect是window下的一个内置对象 // 1. 使用reflect 访问数据     let obj = {         name: '张三',         age: 20     }     console.log(Reflect.get(obj, 'name')); // 张三 // 2.使用Reflect 修改数据     Reflect.set(obj, 'age', 50)     console.log(obj); //3.使用Reflect删除数据  Reflect.deleteProperty(obj, 'name')      console.log(obj); 

vue3响应原理代码

通过Proxy代理,拦截对象中任意属性的变化,包括属性的读取,修改、设置、删除。

通过Reflect 反射对被代理对象的属性进行操作。

    let data = {         name: "张三",         age: 30     }     console.log(Proxy);     // 使用p 对象代理data, Proxy为window 下的内置代理函数     let p = new Proxy(data, {         // 读取属性         get(target, propName) {             // target 就是 data             console.log(`读取p上个${propName}属性`);             return Reflect.get(target, propName)         },         // 修改和设置属性         set(target, propName, value) {             // value 为赋的值             console.log(`修改p的${propName}属性`);             // target[propName] = value             Reflect.set(target, propName, value)         },         //删除属性         deleteProperty(target, propName) {             console.log(`删除p上的${propName}属性`);             // return delete target[propName]             return Reflect.deleteProperty(target, propName)         }     }) 

6、Reactive 与 ref 对比

1、数据定义角度对比:

  • ref用来定义:基本数据类型
  • reactive 用来定义: 对象或数组类型数据

    注意:ref也可以定义对象或数组类型数据,它内部还是通过reactive转换成代理对象

2、原理角度对比:

  • ref通过Object.defineProperty() 的get和set 实现数据的响应式 即(数据劫持)
  • reactive 通过Proxy 实现数据响应式的,并通过Reflect 来操作源对象数据的。

3、从使用角度对比:

  • ref 定义的数据操作时需要使用 .value, 而插值表达式中使用时,不需要使用 .value
  • reactive 定义的数据操作都不需要 .value

7、vue3中的组件传参

组件关系:

父子 props、$panrent

子父 emit自定义事件 refs

兄弟 eventbus中央事件总线 vue3如果需要实现eventbus 安装第三方库mitt

跨层级 provider inject

组件状态共享工具: vuex pinia

1、父传子

  • 在父组件中给子组件设置自定义属性 tit,将要传递的参数赋值给tit属性
<!--父组件 --> <template> <p></p> <Testvue3 :tit="schoolName"> <span>123</span> </Testvue3> </template> <script> import Testvue3 from "@/components/Testvue3"; export default { name: "App", components: { Testvue3 }, setup() { let schoolName = "千锋"; // 定义要传给子组件的数据 return { schoolName, // 要使用的变量抛出去,这样就可以在页面模板中使用该变量 }; }, }; </script> 
  • 在子组件中接收传过来的属性通过props ,这个和vue2 一样没有变化。
<!-- 子组件 --> <template> <p>{ 
  { tit }}</p> <button>点击事件,子传父</button> </template> <script> export default { data() { return {}; }, props: ["tit"], setup(props) { // 参数props即为父组件传过来的参数 console.log(props) return { //setup函数返回值为一个对象 }; }, }; </script> 

2、子传父

  • 给子组件绑定自定义事件,然后在setup中定义该事件对应的方法,因为setup中没有this ,this为undefined,所以vue的开发者为了解决该问题,在setup中提供了2个形参,prop和context
    • props 为父传子的参数
    • context 上下文对象,里面有emit 方法,可以实现子传父
  • 子组件中多了 emits选项,该选项类似于props,接收父组件给子组件绑定的自定义方法,如果不加该选项,vue3 会提示警告。但不影响功能
<!-- 子组件 --> <template> <p>{ 
  { tit }}</p> <button @click="emit">点击事件,子传父</button> </template> <script> import { reactive } from "vue"; export default { data() { return {}; }, emits: ["transfer"], // 在子组件中使用emits配置项,接收父组件给我绑定的自定义事件,用法类似于props, // 不加该配置项,控制台会提示警告 setup(props, context) { console.log(11, props); console.log(22, context); // 定义方法 function emit() { // 子传父 此处不用this,使用context上下文对象 context.emit("transfer", 666); } return { //setup函数返回值为一个对象 emit, }; }, }; </script> 
  • 在父组件接收自定义事件,该事件对应的执行函数的形参就是传过来的数据,这个就和vue2一样啦。
    <!--父组件 --> <template> <p></p> <Testvue3 @transfer="showdata"> <span>123</span> </Testvue3> </template> <script> import Testvue3 from "@/components/Testvue3"; export default { name: "App", components: { Testvue3 }, setup() { function showdata(value) { console.log(value); } return { showdata, }; }, }; </script> 

8、vue3中的计算属性

同vue2不同,使用计算属性需要引入computed 方法

<template> <p>姓:<input type="text" v-model="data.firstname" /></p> <p>名:<input type="text" v-model="data.lastname" /></p> <p>姓名:<input type="text" v-model="data.fullname" /></p> </template> <script> // 引入对应的计算属性方法 import { reactive, computed } from "vue"; export default { name: "App", setup() { let data = reactive({ firstname: "", lastname: "", fullname: "", }); // 计算属性--简写 // data.fullname = computed(() => { // return data.firstname + data.lastname; // }); // 计算属性--完整写法 data.fullname = computed({ get() { return data.firstname + data.lastname; }, set(value) { console.log(value); data.firstname = value.substr(0, 1); data.lastname = value.substr(1); }, }); return { data, }; }, }; </script> 

9、vue3 中的 watch监听器

vue3 中的watch 也是 组合式api中的一个方法,所以使用时,需要引入

<template> <p>{ 
  { sum }} <button @click="sum++">sum++</button></p> <p>{ 
  { fullname }} <button @click="fullname += '-'">修改姓名</button></p> <p> { 
  { userinfo.name }}--{ 
  { userinfo.age }}--{ 
  { userinfo.job.type }}--{ 
  { userinfo.job.salary }}K <button @click="userinfo.age++">修改年龄</button> <button @click="userinfo.job.salary++">修改薪水</button> </p> </template> <script> // 引入对应的计算属性方法 import { ref, watch, reactive } from "vue"; export default { name: "App", setup() { let sum = ref(0); let fullname = ref("张三"); let userinfo = reactive({ name: "李四", age: 20, job: { type: "web开发", salary: 20, }, }); //1、监听ref定义的响应式数据 immediate初始化就执行watch watch(sum, (newvalue, oldvalue) => { console.log(newvalue, oldvalue); },{immediate:true}); //2、 监听ref定义的多个响应式数据,immediate初始化就执行watch watch([sum, fullname], (newvalue, oldvalue) => { console.log(newvalue, oldvalue); }, { immediate: true }); //3、 监听reactive 定义的响应式数据 // 注意:此处oldvalue 无效(新值与旧值一样),默认是深度监听,immediate初始化就执行watch watch( userinfo, (newvalue, oldvalue) => { console.log(newvalue, oldvalue); }, { immediate: true }); return { sum, fullname, userinfo, }; }, }; </script> 

watchwatchEffect 都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式:

  • watch 只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch 会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。
  • watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确。

10、vue3生命周期

1、vue3中的生命周期钩子函数与vue2中基本相同,只有如下发生变化,其他都不变.

  • beforeDestory => beforeUnmount
  • destoryed => unmounted

第一种方式:不使用组合式api的方式使用生命周期函数

<!-- 子组件 --> <template> <p>{ 
  { sum }} <button @click="sum++">sum++</button></p> <!--修改sum数据触发update生命周期 --> </template> <script> import { ref } from "vue"; export default { setup() { let sum = ref(0); return { sum, }; }, 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"); //组件卸载后触发 }, }; </script> 

在app.vue 中引入子组件

<template> <Testvue3 v-if="flag"></Testvue3> <button @click="flag = !flag">显示/隐藏</button> <!--修改flag 触发 beforeUnmount和 unmounted 生命周期--> </template> <script> import { ref } from "vue"; import Testvue3 from "@/components/Testvue3"; export default { name: "App", components: { Testvue3, }, setup() { let flag = ref(true);// 修改flag return { flag, }; }, }; </script> 
  • 第二种方式:通过使用组合式api的形式使用生命周期 ,vue3和vue2.x的生命周期对照表如下:

    setup 等同于 beforeCreate 和created

image-20211205222257250

image-

<!-- 子组件 --> <template> <p>{ 
  { sum }} <button @click="sum++">sum++</button></p> </template> <script> //引入对应的生命周期钩子函数 import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, } from "vue"; export default { setup() { let sum = ref(0); onBeforeMount(() => { console.log("beforeMount"); }); onMounted(() => { console.log("mounted"); }); onBeforeUpdate(() => { console.log("beforeUpdate"); }); onUpdated(() => { console.log("updated"); }); onBeforeUnmount(() => { console.log("beforeUnmount"); }); onUnmounted(() => { console.log("unmounted"); }); return { sum, }; }, }; </script> 

11、vue3中自定义hook函数

hook函数定义:本质是一个函数,将setup中的公共逻辑抽离出来放在一个单独的js文件,这样哪个组件使用导入即可。

实现一个点击页面任意位置,在页面中输出当前点击位置的横纵坐标。

  • 实现代码:未使用hook 钩子函数前
<!-- 子组件 --> <template> <p> <span>鼠标点击位置的X坐标为:{ 
  { point.x }}</span> <span>鼠标点击位置的Y坐标为:{ 
  { point.y }}</span> </p> </template> <script> import { reactive, onMounted, onBeforeUnmount } from "vue"; export default { setup() { let point = reactive({ x: 0, y: 0, }); onMounted(() => { document.onclick = function (event) { point.x = event.pageX; point.y = event.pageY; }; }); onBeforeUnmount(() => { document.onclick = null; }); return { point, }; }, }; </script> 
  • 使用hook 钩子函数 ,首先在src 目录下创建一个hooks文件夹,然后再该目录下创建usepoint.js文件,该文件用来存放抽来出来的公共方法。代码如下:
import { reactive, onMounted, onBeforeUnmount } from "vue"; export function usePoint() {     let point = reactive({         x: 0,         y: 0,     });     onMounted(() => {         document.onclick = function (event) {             point.x = event.pageX;             point.y = event.pageY;         };     });     onBeforeUnmount(() => {         document.onclick = null;     });     return point // 最后抛出该point } 
<!-- 子组件 --> <template> <p> <span>鼠标点击位置的X坐标为:{ 
  { point.x }}</span >, <span>鼠标点击位置的Y坐标为:{ 
  { point.y }}</span> </p> </template> <script> // 在子组件中引入该hook方法 import { usePoint } from "@/hooks/usepoint"; export default { setup() { let point = usePoint(); return { point, }; }, }; </script> 

12、toRef 与 toRefs

定义:toRef 创建一个ref 响应数据

语法:let name = toRef(person,’name’) 将响应对象person中的name属性单独拿出来变成响应属性。

应用:一般用于将响应对象中的某个属性单独提供给外部使用

  • 如下是使用toRef 前的代码: 插值表达式模板中的 person 有点繁琐
<!-- 子组件 --> <template> <div> <p> { 
  { person.name }} -- { 
  { person.age }} -- { 
  { person.job.type }} -- { 
  { person.job.salary }} </p> </div> </template> <script> import { reactive } from "vue"; export default { setup() { let person = reactive({ name: "张三", age: 20, job: { type: "web前端开发", salary: 30, }, }); return { person, }; }, }; </script> 
  • 如下是使用toRef 后 的代码,
<!-- 子组件 --> <template> <div> <p> <!-- 在模板中直接使用name,age,type,salary --> { 
  { name }} -- { 
  { age }} -- { 
  { type }} -- { 
  { salary }} </p> <p> <button @click="name += '-'">修改name</button> <button @click="salary++">修改薪水</button> </p> </div> </template> <script> import { reactive, toRef } from "vue"; export default { setup() { let person = reactive({ name: "张三", age: 20, job: { type: "web前端开发", salary: 30, }, }); // 将person 中的name 属性转换成ref 响应式数据,这样就可以直接在模板中使用了,以此类推 let name = toRef(person, "name"); let age = toRef(person, "age"); let type = toRef(person.job, "type"); let salary = toRef(person.job, "salary"); return { name, age, type, salary, }; }, }; </script> <style scoped> /* @import url(); 引入css类 */ </style> 
  • 使用toRefs 可以将对象中的多个属性转换成响应数据,代码如下:
<!-- 子组件 --> <template> <div> <p> { 
  { name }} -- { 
  { age }} -- { 
  { job.type }} -- { 
  { job.salary }} </p> <p> <button @click="name += '-'">修改name</button> <button @click="job.salary++">修改薪水</button> </p> </div> </template> <script> import { reactive, toRefs } from "vue"; export default { setup() { let person = reactive({ name: "张三", age: 20, job: { type: "web前端开发", salary: 30, }, }); //toRefs返回一个响应对象,该对象中每个属性都变成了响应属性了。这样就可以直接拿来在模板插值表达式中使用了 let person1 = toRefs(person); // console.log(person1); return { ...person1, // 使用后扩展运算符展开对象 }; }, }; </script> <style scoped> /* @import url(); 引入css类 */ </style> 

关于数据响应式设置的问题:

1、如何设置一个响应式数据? ref reactive

2、如何将非响应式数据转为响应式数据? toRef toRefs

3、如何将数据设置为只读数据?不能够修改 readOnly

13、vue3 中的路由

1、首先下载安装vue3 对应的vue-router

npm install vue-router@4 

2、在src目录下新建router目录,在该目录下新建index.js 文件,代码如下

//1. 从vue-router 引入对应的方法createRouter 和 createWebHashHistory import { createRouter, createWebHashHistory } from "vue-router"; //2.配置路由规则 const routes = [     { path: '/home', component: () => import('@/views/Home') },     { path: '/category', component: () => import('@/views/Category') }, ] //3.创建路由对象 const router = createRouter({     // 4. Provide the history implementation to use. We are using the hash history for simplicity here.     history: createWebHashHistory(),     routes, // short for `routes: routes` }) export default router 

3、在main.js 中引入并绑定

// 引入路由  import router from '@/router' // 在全局实例上挂载router,这样每个页面都可以访问路由 createApp(App).use(store).use(router).mount('#app') 

路由参数获取

<template> <div> 新闻页 </div> </template> <script lang="ts"> import { defineComponent } from 'vue' import { useRoute } from 'vue-router'; export default defineComponent({ setup() { // useRoute获取路由参数 const route = useRoute() console.log(route); console.log(route.query.id); return {} } }) </script> <style scoped></style> 

路由方法使用

<template> <div> Index首页 <!-- <button @click="$router.push('/news')">新闻</button> --> <button @click="goNews">新闻</button> </div> </template> <script lang="ts"> import { defineComponent } from 'vue' // 导入路由相关的组合式函数hook use开头的函数 import { useRouter } from 'vue-router' export default defineComponent({ setup() { // 组合式函数必须先调用一次 // useRouter 获取路由操作方法 const router = useRouter() const goNews = () => { // this.$router.push() // console.log(router); router.push('/news') } return { goNews } } }) </script> <style scoped></style> 

14、vue3 中的vuex

1、首先需要安装vuex

npm install vuex@next --save 

2、在src目录下创建store 文件夹,该目录下创建index.js文件,代码如下:

import { createStore } from 'vuex' // console.log(createStore); export default createStore({     state: {         count: 100     },     getters: {         getCount(state) {             return state.count * 2         }     },     mutations: {         setTestA(state, value) {             state.count = value         }     },     actions: {     },     modules: {     } }) 

3、在main.js 引入然后使用挂载

import { createApp } from 'vue' import App from './App.vue' // 引入 store import store from '@/store' console.log(store); // 挂载使用 这样全局就可以使用store了 createApp(App).use(store).mount('#app') // console.log(createApp(App)); 

4.在页面组件中使用store

<!-- 子组件 --> <template> { 
  { count }} ----{ 
  { double }} <button @click="updateFun">修改数据</button> </template> <script> import { computed } from "vue"; import { useStore } from "vuex"; export default { setup() { const store = useStore(); // 必须以计算属性形式输出,否则无法修改state中的数据 如count const count = computed(() => { return store.state.count; }); const double = computed(() => { return store.getters.getCount; }); const updateFun = () => { store.commit("setTestA", 20); }; return { count, double, updateFun, }; }, }; </script> 

vue官方在使用vue3时,更加推荐使用Pinia状态管理。Pinia和vuex实际一个开发团队在维护。vuex最终版本是4,可以将Pinia看作是vuex5。

src\stores\counter.ts

import { ref, computed } from 'vue' // defineStore store构造函数 import { defineStore } from 'pinia' export const useCounterStore = defineStore('counter', () => {   // 初始化state   const count = ref(0)   // 使用计算属性获取结果   const doubleCount = computed(() => count.value * 2)   // actions方法  修改state的操作方法   function increment() {     count.value++     // console.log(count)   }   // 将需要外部使用到的值和方法按需导出   return { count, doubleCount, increment } }) 

src\App.vue

<template> <div> <button @click="increment"> { 
  { store.count }}</button> <div>{ 
  { store.doubleCount }}</div> </div> </template> <script lang="ts"> import { defineComponent, toRef } from 'vue' // 将usestore引入 import { useCounterStore } from './stores/counter' export default defineComponent({ setup() { // 调用store获取对象 const store = useCounterStore() console.log(store); // 从store对象中获取state值和修改state的方法 return { store, increment: store.increment } } }) </script> <style scoped></style> 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/111396.html

(0)
上一篇 2026-01-25 08:33
下一篇 2026-01-25 09:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信