• Vue


    Vue

    Vue (读音 /vjuː/,类似于 view) 是一套 **构建用户界面 ** 的 渐进式框架。

    所谓渐进式就是循序渐进,不一定非得把Vue中的所有API都学完才能开发Vue,可以学一点开发一点。

    Vue2官网:https://v2.cn.vuejs.org/

    1. 创建Vue实例

    1)从官网下载vue.js文件

    2)在html文件中引入vue.js

    3)创建vue实例

    DOCTYPE html>
    <head>
        <meta charset="UTF-8">
        <title>demotitle>
    
    head>
    <body>
    <div id="app">{{msg}}div>
    <script src="vue.js">script>
    <script>
        new Vue({
            el: "#app",
            data: {
                msg:"hello Vue"
            }
        })
    script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2. 插值表达式

    插值表达式是一种Vue的模板语法,我们可以用插值表达式渲染出Vue提供的数据或表达式的结果。

    语法:{{ xxx }}

    {{title}}

    {{nickName.toUpperCase()}}

    {{age >= 18 ? '成年':'未成年'}}

    {{obj.name}}

    {{fn()}}

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3. 响应式特性

    响应式简单理解就是数据变,视图对应变。

    data中的数据, 最终会被添加到实例上

    ① 访问数据: “实例.属性名”

    ② 修改数据: “实例.属性名”= “值”

    请添加图片描述

    4. 常用指令

    概念:指令(Directives)是 Vue 提供的带有 v- 前缀 的 特殊 标签属性

    vue 中的指令按照不同的用途可以分为如下 6 大类:

    • 内容渲染指令(v-html、v-text)
    • 条件渲染指令(v-show、v-if、v-else、v-else-if)
    • 事件绑定指令(v-on)
    • 属性绑定指令 (v-bind)
    • 双向绑定指令(v-model)
    • 列表渲染指令(v-for)

    4.1 内容渲染指令

    内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下2 个:

    1)v-text(类似innerText)

    使用语法:

    hello

    ,意思是将 uame 值渲染到 p 标签中。

    类似 innerText,使用该语法,会覆盖 p 标签原有内容。

    2)v-html(类似 innerHTML)

    使用语法:

    hello

    ,意思是将 intro 值渲染到 p 标签中

    类似 innerHTML,使用该语法,会覆盖 p 标签原有内容。

    类似 innerHTML,使用该语法,能够将HTML标签的样式呈现出来。

    示例:

    <div id="app">
        <h2>个人信息h2>
        
        <p v-text="uname">姓名:p>
        <p v-html="intro">简介:p>
    div>
    
    <script>
        const app = new Vue({
            el:'#app',
            data:{
                uname:'张三',
                intro:'

    这是一个非常优秀的boy

    ' } }) script>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4.2 条件渲染指令

    条件判断指令,用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是:

    1)v-show

    1. 作用: 控制元素显示隐藏
    2. 语法: v-show = “表达式” 表达式值为 true 显示, false 隐藏
    3. 原理: 切换 display:none 控制显示隐藏
    4. 场景:频繁切换显示隐藏的场景

    2)v-if

    1. 作用: 控制元素显示隐藏(条件渲染)
    2. 语法: v-if= “表达式” 表达式值 true显示, false 隐藏
    3. 原理: 基于条件判断,是否创建 或 移除元素节点
    4. 场景: 要么显示,要么隐藏,不频繁切换的场景

    示例:

    <script src="vue.js">script>
    <div id="app">
        <div class="box" v-show="flag">我是v-show控制的盒子div>
        <div class="box" v-if="flag">我是v-if控制的盒子div>
    div>
    
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                flag: true
            }
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3)v-else 和 v-else-if

    1. 作用:辅助v-if进行判断渲染
    2. 语法:v-else v-else-if=“表达式”
    3. 需要紧接着v-if使用

    示例:

    <script src="vue.js">script>
    <div id="app">
        <p v-if="gender==1">性别:♂ 男p>
        <p v-else>性别:♀ 女p>
        <hr>
        <p v-if="score>=90">成绩评定Ap>
        <p v-else-if="score>=80">成绩评定Bp>
        <p v-else-if="score>=70">成绩评定Cp>
        <p v-else>成绩评定Dp>
    div>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                gender: 1,
                score: 95
            }
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4.3 事件绑定指令

    使用Vue时,如需为DOM注册事件,及其的简单,语法如下:

    • v-on: 简写为 @

    示例一:内联语句

    <div id="app">
        
        <button @click="count--">-button>
        <span>{{ count }}span>
        <button v-on:click="count++">+button>
    div>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                count: 100
            }
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    示例二:处理函数

    <div id="app">
        <button @click="handleClick">切换显示隐藏button>
        <h1 v-show="isShow">hello Vueh1>
    div>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                isShow: true
            },
            methods:{
                handleClick(e){
                    this.isShow = !this.isShow;
                    console.log(e);
                }
            }
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    注意:

    • 事件处理函数应该写到一个跟data同级的配置项(methods)中

    • methods中的函数内部的this都指向Vue实例

    • 如果不传递任何参数,则方法无需加小括号;methods方法中可以直接使用 e 当做事件对象

    • 如果传递了参数,则实参 $event 表示事件对象,固定用法。

    4.4 单向属性绑定指令

    1. **作用:**动态设置html的标签属性 比如:src、url、title
    2. 语法:**v-bind:**属性名=“表达式”
    3. **v-bind:**可以简写成 => :

    示例:

    <div id="app">
        <img v-bind:src="imgUrl" v-bind:title="msg" alt="" width="200px">
        <img :src="imgUrl" :title="msg" alt="" width="200px">
    div>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                imgUrl: './1.png',
                msg: 'hello Vue'
            }
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.5 双向属性绑定指令

    所谓双向绑定就是数据改变后,呈现的页面结果会更新,页面结果更新后,数据也会随之而变。

    作用:表单元素(input、radio、select)使用,双向绑定数据,可以快速 获取设置 表单元素内容

    **语法:**v-model=“变量”

    示例:

    <div id="app">
        账户:<input type="text" v-model="username"> <br><br>
        密码:<input type="password" v-model="password"> <br><br>
    div>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                username: '',
                password: ''
            },
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    <template>
      <div>
        <input type="checkbox" id="checkbox" v-model="checked">
        <label for="checkbox">{{ checked }}label>
      div>
    template>
    
    <script>
    export default {
      data() {
        return {
          checked: false
        }
      }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    原理:v-model本质上是一个语法糖。例如应用在输入框上,就是value属性 和 input事件 的合写

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.6 列表渲染指令

    Vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。

    v-for 指令需要使用 (item, index) in arr 形式的特殊语法,其中:

    • item 是数组中的每一项
    • index 是每一项的索引,不需要可以省略
    • arr 是被遍历的数组

    此语法也可以遍历对象和数字

    示例1:

    <div id="app">
    
        <div v-for="(value, key, index) in object">{{key}} : {{value}}div>
    
    
        <p v-for="item in 10">{{item}}p>
    
    div>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                object:{
                    name: "obejct1",
                    age: "18",
                    gender: "male"
                }
            },
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    v-for中的key属性作为唯一标识,便于Vue进行列表项的正确排序复用

    <div v-for="item in items" :key="item.id">
      {{ item.name }}
    div>
    
    • 1
    • 2
    • 3

    注意:

    • :key表示key的值是动态绑定的。

    • key 的值只能是字符串 或 数字类型

    • key 的值必须具有唯一性

    • 推荐使用 id 作为 key(唯一),不推荐使用 index 作为 key(会变化,不对应)

    5. 修饰符

    修饰符(Modifiers)是一种特殊的后缀,用于指示Vue对某些绑定的DOM事件或属性绑定行为进行特别处理。它们通常以点(.)开始,添加到指令后,用来执行一些特定的操作或行为调整。

    5.1 事件修饰符

    事件修饰符允许我们处理DOM事件的细节,例如事件冒泡、事件捕获、事件修饰键等。一用的事件修饰符:

    • .stop - 调用event.stopPropagation(),阻止事件继续传播。

    • .prevent - 调用event.preventDefault(),阻止事件的默认行为。

    • .capture - 使用事件捕获模式添加事件监听器。

    • .once - 事件将只触发一次。

    5.2 键盘事件修饰符

    键盘事件修饰符用于监听键盘事件,使得只有在特定键被按下时才触发某个操作。例如:

    • .enter
    • .delete(捕获“删除”和“退格”键)
    • .space
    • .up
    • .down

    5.3 修饰符串联

    修饰符可以串联,即可以在同一个指令上使用多个修饰符,例如:

    <button @click.stop.prevent="doThat">点击我button>
    
    • 1

    上述代码同时使用了.stop.prevent修饰符,既停止事件冒泡也阻止默认行为。

    5.4 v-model 修饰符

    用于创建双向数据绑定的v-model指令也支持几个修饰符,来定制如何绑定和监听输入控件的值:

    • .lazy - 取代input事件监听更新,使用change事件。
    • .number - 输入字符串转为有效的数字。
    • .trim - 输入去除首尾空格。

    6. computed计算属性

    计算属性是一种特殊的属性,它可以根据依赖的数据动态计算出一个新的值。计算属性的值会被 Vue.js 缓存,只有当依赖的数据发生改变时,才会重新计算这个属性的值。

    计算属性的特点:

    1. 数据变化时会重新计算,提高了性能。适合用在复杂逻辑的计算上。
    2. 计算属性的结果会被缓存,依赖数据改变之前,多次访问计算属性会直接返回之前的计算结果,而不会重新计算。

    示例:

    <div id="app">
        <div>a + b 的结果为:{{sum}}div>
    div>
    
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                a: 10,
                b: 20
            },
            computed: {
                sum: function (){
                    return this.a + this.b;
                }
            }
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    计算属性默认的简写,只能读取访问,不能 “修改”,如果要 “修改” 需要写计算属性的完整写法

    请添加图片描述

    示例:

    <div id="app">
        姓:<input type="text" v-model="firstName"> +
        名:<input type="text" v-model="lastName"> =
        {{ name }}<br><br>
        <button @click="name='张飞'">改名卡button>
    div>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                firstName: '刘',
                lastName: '备'
            },
            computed: {
                name: {
                    get: function () {
                        return this.firstName + this.lastName
                    },
                    set: function (newValue) {
                        this.firstName = newValue.charAt(0);
                        this.lastName = newValue.slice(1);
                    }
                }
            }
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    7. watch侦听器

    作用:监视数据变化,执行一些业务逻辑或异步操作

    1)简化语法:声明在data同级的配置项中

    watch: {
      // 该方法会在数据变化时,触发执行
      数据属性名 (newValue, oldValue) {
        一些业务逻辑 或 异步操作。 
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    简化写法示例:

    <div id="app">
        {{ count }}
        <button @click="count++">count++button>
    div>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                count: 0,
            },
            watch: {
                count: function (oldVal, newVal){
                    console.log(oldVal + "->" + newVal)
                }
            }
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2)完整语法示例:

    {{ count }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    注意:

    • deep为深度监听,即被监听的对象属性发生变化时也会触发。(若不开启则只有对象引用发生变化时才会触发)
    • immediate表示在数据第一次加载时也会触发。

    8. 生命周期

    生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁

    1.创建阶段:创建响应式数据

    2.挂载阶段:渲染模板

    3.更新阶段:修改数据,更新视图

    4.销毁阶段:销毁Vue实例

    请添加图片描述

    8.1 生命周期钩子

    以下是Vue的生命周期钩子:

    • beforeCreate:组件创建之后遇到的第一个生命周期函数,这个阶段 data 和 methods 以及 dom 结构都未
      被初始化,也就是获取不到 data 的值,不能调用 methods 中的函数
    • created:这个阶段组件的 data 和 methods 中的方法已初始化结束,可以访问,但是 dom 结构未初始化,页面未渲染
    • beforeMount:当模板在内存中编译完成,此时内存中的模板结构还未渲染至页面上,看不到真实的数据
    • mounted:此时,页面渲染好,用户看到的是真实的页面数据, 生命周期创建阶段完毕,进入到了运行中的阶段
    • beforeUpdate:当执行此函数,数据池的数据新的,但是页面是旧的
    • updated:页面已经完成了更新,此时,data 数据和页面的数据都是新的
    • beforeDestroy:当执行此函数时,组件即将被销毁,但是还没有真正开始销毁,此时组件的 data、methods数据或方法 还可被调用
    • destroyed:组件已经完成了销毁

    请添加图片描述

    示例:

    <div id="app">
        {{ count }}
        <button @click="count++">count++button>
    div>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                count: 0,
            },
            beforeUpdate: function (){
                console.log(this.count);
            }
        })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    9. 工程化开发和脚手架

    Vue的工程化开发是指通过一系种工具和规范,将Vue的开发流程进行标准化、自动化,提高开发效率和项目质量。它包括了项目初始化、开发、构建、部署、测试等环节。

    9.1 Vue CLI

    Vue的脚手架是Vue CLI,它是一个全局安装的命令行工具,提供了项目创建、开发和构建等功能。Vue CLI能够帮助开发者快速创建Vue项目,它预设了一些项目模板,包括了webpack、Babel、ESLint等开发工具的配置,让开发者可以专注于编写业务代码,而不需要花费大量时间去配置这些工具。

    使用步骤:

    1. 全局安装(只需安装一次即可) yarn global add @vue/cli 或者 npm i @vue/cli -g
    2. 查看vue/cli版本: vue --version
    3. 创建项目架子:vue create project-name(项目名不能使用中文)
    4. 启动项目:yarn serve 或者 npm run serve(命令不固定,找package.json)

    9.2 项目目录介绍

    请添加图片描述

    9.3 运行流程

    请添加图片描述

    10. 组件化开发

    组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。

    好处:便于维护,利于复用 → 提升开发效率。

    请添加图片描述

    组件由三部分构成:

    • template:结构 (有且只能一个根元素)
    • script: js逻辑
    • style: 样式 (可支持less,需要装包)

    10.1 根组件 App.vue

    App.vue为整个应用最上层的组件,包裹所有普通小组件

    请添加图片描述

    10.2 普通组件局部注册

    特点:只能在注册的组件内使用

    1)创建三个组件

    Header:

    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Main:

    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Footer:

    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2)引入组件并在局部注册

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    10.3 普通组件全局注册

    特点:全局注册的组件,在项目的任何组件中都能使用

    在main.js中注册:

    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router'
    import MyComponent from './components/MyComponent.vue'
    
    const app = createApp(App)
    
    app.component('my-component', MyComponent)
    
    app.use(router).mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    10.4 scoped解决样式冲突

    写在组件中的样式会 全局生效 → 因此很容易造成多个组件之间的样式冲突问题。

    1. 全局样式: 默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响

    2. 局部样式: 可以给组件加上scoped 属性,可以让样式只作用于当前组件

    <template>
        <div class="base-one">
            BaseOne
        div>
    template>
    
    <script>
        export default {
    
        }
    script>
    
    <style scoped>
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    原理:

    1. 当前组件内标签都被添加data-v-hash值 的属性
    2. css选择器都被添加 [data-v-hash值] 的属性选择器

    最终效果: 必须是当前组件的元素, 才会有这个自定义属性, 才会被这个样式作用到

    10.5 组件中的data

    一个组件的 data 选项必须是一个函数。目的是为了:保证每个组件实例,维护独立的一份数据对象。

    每次创建新的组件实例,都会新执行一次data 函数,得到一个新对象。

    请添加图片描述

    baseCount.vue:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    App.vue:

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    11. 组件通信

    组件通信,就是指组件与组件之间的数据传递

    • 组件的数据是独立的,无法直接访问其他组件的数据。
    • 想使用其他组件的数据,就需要组件通信

    11.1 父子间通信

    父组件通过 props 将数据传递给子组件

    子组件利用 $emit 通知父组件修改更新

    请添加图片描述

    父向子传值步骤:

    1. 给子组件以添加属性的方式传值
    2. 子组件内部通过props接收
    3. 模板中直接使用 props接收的值

    子向父传值步骤:

    1. $emit触发事件,给父组件发送消息通知
    2. 父组件监听$emit触发的事件
    3. 提供处理函数,在函数的性参中获取传过来的参数

    Son.vue:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    App.vue:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    props完整写法:

    props: {
      校验的属性名: {
        type: 类型,  // Number String Boolean ...
        required: true, // 是否必填
        default: 默认值, // 默认值
        validator (value) {
          // 自定义校验逻辑
          return 是否通过校验
        }
      }
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    11.2 非父子通信

    父组件 provide提供数据

    子/孙组件 inject获取数据

    父组件:

    export default {
      provide () {
        return {
           // 普通类型【非响应式】
           color: this.color, 
           // 复杂类型【响应式】
           userInfo: this.userInfo, 
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    子/孙组件:

    export default {
      inject: ['color','userInfo'],
      created () {
        console.log(this.color, this.userInfo)
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意:

    • provide提供的简单类型的数据不是响应式的,复杂类型数据是响应式。(推荐提供复杂类型数据)
    • 子/孙组件通过inject获取的数据,不能在自身组件内修改

    v-model简化代码

    v-model其实就是 :value 和 @input事件的简写

    • 子组件:props通过value接收数据,事件触发 input
    • 父组件:v-model直接绑定数据

    子组件:

    
    props: {
      value: String
    },
    methods: {
      handleChange (e) {
        this.$emit('input', e.target.value)
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    父组件:

    
    
    • 1

    .sync修饰符

    作用:可以实现 子组件父组件数据双向绑定,简化代码

    本质:.sync修饰符 就是 :属性名@update:属性名 合写

    父组件:

    //.sync写法
    
    ---------------------------------------
    //完整写法
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    子组件:

    props: {
      visible: Boolean
    },
    
    this.$emit('update:visible', false)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    12. ref和$refs

    ref 是 Vue.js 中的一个特殊属性,可以用来绑定到渲染的 DOM 元素或子组件上。当 ref 和 HTML 元素一起使用时,ref 的值将是该元素;当 ref 和组件一起使用时,ref 的值将是组件实例。

    $refs 是一个对象,持有已注册过 ref 的所有 DOM 元素和组件实例。它可以在组件的方法中通过 this.$refs 来访问。

    示例:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    13. $nextTick

    $nextTick 用于在下一次 DOM 更新循环结束之后延迟执行一段代码。在 DOM 更新之后,基于新的 DOM 状态来执行一些操作时非常有用。

    示例:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    14. 自定义指令

    • 内置指令:v-html、v-if、v-bind、v-on… 这都是Vue给咱们内置的一些指令,可以直接使用

    • 自定义指令:同时Vue也支持让开发者,自己注册一些指令。这些指令被称为自定义指令,每个指令都有自己各自独立的功能

    示例一:局部注册

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    示例二:全局注册

    main.js:

    import { createApp } from "vue";
    import App from "./App.vue";
    import router from "./router";
    
    const app = createApp(App);
    app.directive("color", (el, binding) => {
      el.style.color = binding.value; // 获取指令的值
    });
    app.use(router).mount("#app");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    app.vue:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    15. 插槽

    作用:让组件内部的一些 结构 支持 自定义

    15.1 默认插槽

    语法:

    1. 组件内需要定制的结构部分,改用****占位
    2. 使用组件时, ****标签内部, 传入结构替换slot
    3. 给插槽传入内容时,可以传入纯文本、html标签、组件

    示例:

    子组件:

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    父组件:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    15.2 默认值

    封装组件时,可以为预留的 插槽提供后备内容(默认内容)。

    示例:

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    15.3 具名插槽

    当一个组件内有多处结构,需要外部传入标签进行定制时就需要给每个结构定义名字加以区分。

    语法:

    • 多个slot使用name属性区分名字
    • template配合v-slot:名字来分发对应标签,其中v-slot可简写成#

    示例:

    子组件:

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    父组件:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    15.4 作用域插槽

    定义slot 插槽的同时, 是可以传值的。给 插槽 上可以 绑定数据,将来 使用组件时可以用

    使用方式:

    1)给 slot 标签, 以 添加属性的方式传值

    
    
    • 1

    2)所有添加的属性, 都会被收集到一个对象中

    { id: 3, msg: '测试文本' }
    
    • 1

    3)在template中, 通过 #插槽名= "obj" 接收,默认插槽名为 default

    
      
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    示例:

    子组件:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    父组件:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    16. 路由

    Vue路由是单页面应用的核心,所有的页面跳转都通过路由来完成。

    Vue Router是路由管理器

    配置路由:

    // 引入 vue-router 的两个方法:createRouter 和 createWebHistory
    import { createRouter, createWebHistory } from 'vue-router'
    // 引入 HomeView 组件
    import HomeView from '../views/HomeView.vue'
    
    // 定义路由映射
    const routes = [
      {
        // 当用户访问根路径(即 '/')时,将会渲染 HomeView 组件
        path: '/home',
        name: 'home',
        component: HomeView
      },
      {
        // 当用户访问 '/about' 路径时,将会渲染 AboutView 组件
        // 这里使用了懒加载的方式来引入 AboutView 组件,即当路由被访问时才加载对应组件,可以提高首屏加载速度
        path: '/about',
        name: 'about',
        component: () => import('../views/AboutView.vue')
      }
    ]
    
    // 创建 router 实例
    const router = createRouter({
      // 使用 HTML5 的 History 路由模式
      history: createWebHistory(process.env.BASE_URL),
      // 应用的路由映射
      routes
    })
    
    // 导出 router 实例
    export default router
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    其中路由模式:

    • hash路由(默认) 例如: http://localhost:8080/#/home
    • history路由(常用) 例如: http://localhost:8080/home

    16.1 声明式导航

    App.vue:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    我们可以通过在样式中添加.router-link-active来设置选中链接的样式,从而实现选中高亮的效果。例如,我们可以设置选中链接的颜色为蓝色:

    <style scoped>
    /* 其他样式 */
    
    .router-link-active {
      background-color: blue;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    .router-link-active是模糊匹配,只要路径中含有配置路由即可高亮(使用较多)。

    .router-link-exact-active是精确匹配,路径必须与配置路由一致才可匹配。

    在路由配置时使用linkActiveClasslinkExactActiveClass也可自己定义类目

    const router = new VueRouter({
      routes: [...],
      linkActiveClass: 'active', // 配置模糊匹配的类名
      linkExactActiveClass: 'exact-active' // 配置精确匹配的类名
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    16.2 声明式导航传参

    我们可以通过两种方式,在跳转的时候把所需要的参数传到其他页面中

    1)查询参数传参

    • 传参方式:
    • 获取参数:$router.query.参数名

    2)动态路由传参

    • 配置动态路由:动态路由后面的参数可以随便起名,但要有语义

      const router = new VueRouter({
        routes: [
          ...,
          { 
            path: '/search/:words', 
            component: Search 
          }
        ]
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    • 配置导航链接:to="/path/参数值"

    • 对应页面组件接受参数:$route.params.参数名

    示例一:查询参数传参

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    示例二:动态路由传参

    router:

    const routes = [
      {
        path: "/home",
        name: "home",
        component: HomeView,
      },
      {
        path: "/about/:key",
        name: "about",
        component: () => import("../views/AboutView.vue"),
      },
    ];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    App.vue:

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    about.vue:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注意:

    /search/:key 表示,必须要传参数。如果不传参数,也希望匹配,可以加个可选符

    {
       path: "/about/:key?",
       name: "about",
       component: () => import("../views/AboutView.vue"),
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    16.3 重定向

    语法:{ path: 匹配路径, redirect: 重定向到的路径 }

    示例:

    const routes = [
      {
        path: "/",
        redirect: "/home",
      },
      {
        path: "/home",
        name: "home",
        component: HomeView,
      },
      {
        path: "/about/:key",
        name: "about",
        component: () => import("../views/AboutView.vue"),
      },
    ];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    16.4 404界面

    当路径找不到匹配时,需要给个提示页面

    path: “*” (任意路径) – 前面不匹配就命中最后这个

    import NotFind from '@/views/NotFind'
    
    const router = new VueRouter({
      routes: [
        ...
        { path: '*', component: NotFind } //最后一个
      ]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    16.5 路由跳转方式

    1)query传参跳转

    //简单写法
    this.$router.push('/路径?参数名1=参数值1&参数2=参数值2')
    //完整写法
    this.$router.push({
      path: '/路径',
      query: {
        参数名1: '参数值1',
        参数名2: '参数值2'
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    示例:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2)动态路由传参

    //简单写法
    this.$router.push('/路径/参数值')
    //完整写法
    this.$router.push({
      path: '/路径/参数值'
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    17. Vuex

    Vuex 是一个插件,可以帮我们管理 Vue 通用的数据 (多组件共享的数据)。例如:购物车数据 个人信息。

    17.1 快速入门

    1)安装

    安装vuex与vue-router类似,vuex是一个独立存在的插件,如果脚手架初始化没有选 vuex,就需要额外安装。

    yarn add vuex@3 或者 npm i vuex@3
    
    • 1

    2)新建 store/index.js 专门存放 vuex

    为了维护项目目录的整洁,在src目录下新建一个store目录其下放置一个index.js文件。 (和 router/index.js 类似)

    3)创建仓库 store/index.js

    // 导入 vue
    import Vue from "vue";
    // 导入 vuex
    import Vuex from "vuex";
    // vuex也是vue的插件, 需要use一下, 进行插件的安装初始化
    Vue.use(Vuex);
    
    // 创建仓库 store
    const store = new Vuex.Store();
    
    // 导出仓库
    export default store;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4)在 main.js 中导入挂载到 Vue 实例上

    import Vue from 'vue'
    import App from './App.vue'
    import store from './store'
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App),
      store
    }).$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    此刻起,就成功创建了一个空仓库

    17.2 state

    State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储。

    打开项目中的store.js文件,在state对象中可以添加我们要共享的数据。

    设置数据:

    // 创建仓库 store
    const store = new Vuex.Store({
      // state 状态, 即数据, 类似于vue组件中的data,
      // 区别:
      // 1.data 是组件自己的数据, 
      // 2.state 中的数据整个vue项目的组件都能访问到
      state: {
        count: 101
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    获取数据语法:

    获取 store:
     1.Vue模板中获取 this.$store
     2.js文件中获取 import 导入 store
    
    
    模板中:     {{ $store.state.xxx }}
    组件逻辑中:  this.$store.state.xxx
    JS模块中:   store.state.xxx
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    示例:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    17.3 mapState

    mapState是辅助函数,帮助我们把store中的数据映射到 组件的计算属性中, 它属于一种方便的用法

    用法:

    1)导入mapState (mapState是vuex中的一个函数)

    import { mapState } from 'vuex'
    
    • 1

    2)采用数组形式引入state属性

    mapState(['count']) 
    
    • 1

    上面代码类似于:

    count () {
        return this.$store.state.count
    }
    
    • 1
    • 2
    • 3

    3)利用展开运算符将导出的状态映射给计算属性

      computed: {
        ...mapState(['count'])
      }
    
    • 1
    • 2
    • 3

    示例:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    17.4 mutations

    在组件中无法直接修改store中的数据,需要借助mutation修改数据。

    mutations是一个对象,对象中存放修改state的方法

    1)在store.js中添加方法:

    state: {
    	count: 0,
    },
    mutations: {
        addCount1(state) {
          state.count++;
        },
        addCount2(state, num) {
          state.count += num;
        },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2)调用方法:

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    17.5 mapMutations

    mapMutations和mapState很像,它把位于mutations中的方法提取了出来,我们可以将它导入

    import  { mapMutations } from 'vuex'
    methods: {
        ...mapMutations(['addCount'])
    }
    
    • 1
    • 2
    • 3
    • 4

    上面代码的含义是将mutations的方法导入了methods中,等价于

    methods: {
          // commit(方法名, 载荷参数)
          addCount () {
              this.$store.commit('addCount')
          }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    此时,就可以直接通过this.addCount调用了

    
    
    • 1

    17.6 actions

    actions负责进行异步操作

    1)添加actions方法

    mutations: {
      changeCount (state, newCount) {
        state.count = newCount
      }
    }
    
    
    actions: {
      setAsyncCount (context, num) {
        // 一秒后, 给一个数, 去修改 num
        setTimeout(() => {
          context.commit('changeCount', num)
        }, 1000)
      }
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2)组件中通过dispatch调用方法

    setAsyncCount () {
      this.$store.dispatch('setAsyncCount', 666)
    }
    
    • 1
    • 2
    • 3

    17.7 mapActions

    mapActions 是把位于 actions中的方法提取了出来,映射到组件methods中

    import { mapActions } from 'vuex'
    methods: {
       ...mapActions(['changeCountAction'])
    }
    
    • 1
    • 2
    • 3
    • 4

    直接通过 this.方法 就可以调用

    
    
    • 1

    17.8 getters

    除了state之外,有时我们还需要从state中筛选出符合条件的一些数据,这些数据是依赖state的,此时会用到getters

    例如,state中定义了list,为1-10的数组,

    state: {
        list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    }
    
    • 1
    • 2
    • 3

    组件中,需要显示所有大于5的数据,正常的方式,是需要list在组件中进行再一步的处理,但是getters可以帮助我们实现它。

    1)定义getters

    getters: {
        // getters函数的第一个参数是 state
        // 必须要有返回值
         filterList:  state =>  state.list.filter(item => item > 5)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2)使用getters

    原生方式:

    {{ $store.getters.filterList }}
    • 1

    辅助函数:

    computed: {
        ...mapGetters(['filterList'])
    }
    
    • 1
    • 2
    • 3
     
    {{ filterList }}
    • 1

    17.9 module

    如果把所有的状态都放在state中,当项目变得越来越大的时候,Vuex会变得越来越难以维护。由此,有了Vuex的模块化。

    请添加图片描述

    在store目录下创建一个module文件夹,定义两个模块 usersetting

    user中管理用户的信息状态 userInfo modules/user.js

    const state = {
      userInfo: {
        name: 'zs',
        age: 18
      }
    }
    
    const mutations = {}
    
    const actions = {}
    
    const getters = {}
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions,
      getters
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    setting中管理项目应用的 主题色 theme,描述 desc, modules/setting.js

    const state = {
      theme: 'dark'
      desc: '描述真呀真不错'
    }
    
    const mutations = {}
    
    const actions = {}
    
    const getters = {}
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions,
      getters
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    store/index.js文件中的modules配置项中,注册这两个模块

    import user from './modules/user'
    import setting from './modules/setting'
    
    const store = new Vuex.Store({
        modules:{
            user,
            setting
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用模块中的数据, 可以直接通过模块名访问 $store.state.模块名.xxx => $store.state.setting.desc

    也可以通过 mapState 映射

    获取数据:

    $store直接访问

    $store.state.user.userInfo.name
    
    • 1

    mapState辅助函数访问(需要开启命名空间)

    ...mapState('user', ['userInfo']),
    ...mapState('setting', ['theme', 'desc']),
    
    • 1
    • 2

    使用模块中 getters 中的数据:

    1)直接通过模块名访问 $store.getters['模块名/xxx ']

    2)通过 mapGetters 映射

    • 默认根级别的映射 mapGetters([ 'xxx' ])
    • 子模块的映射 mapGetters('模块名', ['xxx']) - 需要开启命名空间

    获取模块内的mutations方法:

    1)直接通过 store 调用 $store.commit('模块名/xxx ', 额外参数)

    2)通过 mapMutations 映射

    • 默认根级别的映射 mapMutations([ ‘xxx’ ])
    • 子模块的映射 mapMutations(‘模块名’, [‘xxx’]) - 需要开启命名空间

    获取模块内的actions方法:

    1)直接通过 store 调用 $store.dispatch('模块名/xxx ', 额外参数)

    2)通过 mapActions 映射

    • 默认根级别的映射 mapActions([ ‘xxx’ ])
    • 子模块的映射 mapActions(‘模块名’, [‘xxx’]) - 需要开启命名空间

    18. Vue3

    官网:https://cn.vuejs.org/

    18.1 setup

    setup 函数是 Vue 组件中的新选项,它是所有组合式 API 特性的入口点。它的主要目的是替代 Vue 2 中的 data、methods、computed 和 lifecycle hooks 等选项,提供一个更灵活和组织性更强的方式来组织组件逻辑。

    特点:

    1. 执行时机setup 函数在组件创建之前执行,此时组件的 props 已经被解析,并且可以在函数内访问。这使得 setup 成为定义响应式状态和其他响应式逻辑的理想位置。
    2. 参数setup 函数接收两个参数:
      • props:一个包含组件接收的所有 props 的对象。注意,Vue 对这些 props 进行了代理,你应当避免解构它们,以保持响应性。
      • context:一个普通的 JavaScript 对象,包含了 Vue 组件实例的 attrsslotsemit 等属性。
    3. 返回值setup 函数的返回值可以是一个对象,该对象的属性将会被暴露给组件的其它部分(如模板或其他选项API),或者返回一个渲染函数。
    4. 响应式状态: 在 setup 中,你可以使用 refreactive 来创建响应式状态。ref 用于定义响应式的基本类型值,而 reactive 则用于对象或数组。
    5. 生命周期钩子: Vue 3 的生命周期钩子也可以在 setup 中使用,但它们的名称有所更改,如 onMountedonUpdatedonUnmounted 等。

    示例:

    import { ref, onMounted } from 'vue';
    
    export default {
      setup(props, { emit }) {
        const count = ref(0);
    
        function increment() {
          count.value++;
          emit('update:count', count.value);
        }
    
        onMounted(() => {
          console.log('Component is mounted!');
        });
    
        return { count, increment };
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Vue 3 中引入了 setup 语法糖 script setup。这是一种新的语法糖,允许在

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    18.2 reactive和ref

    reactive: 接收一个对象类型的数据,返回一个响应式的对象

    示例:

    import { reactive } from 'vue'
    
    const state = reactive({
      count: 100
    })
    
    const setCount = () => {
      state.count++
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ref: 接收简单类型 或 复杂类型,返回一个响应式的对象

    本质:是在原有传入数据的基础上,外层包了一层对象,包成了复杂类型,再借助 reactive 实现的响应式

    注意点:

    • 脚本中访问数据,需要通过 .value
    • 在template中,.value不需要加 (帮我们扒了一层)
    • 推荐声明数据统一使用ref

    示例:

    import { ref } from 'vue'
    const count = ref(0)
    const setCount = () => {
      count.value++
    }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    18.3 computed

    在 Vue 组件中使用 computed,可以让我们基于现有数据动态计算新的数据值,而且这些值会在依赖的响应式数据发生变化时自动更新。

    示例:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    18.4 watch

    watch 用于观察 Vue 实例上的响应式数据的变化。当需要在数据变化时执行一些操作(如数据获取、验证或复杂的逻辑)时,watch 是非常有用的。

    示例:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    可选参数:

    • deep :用于深度监听对象的内部变化
    • immediate :使得侦听器在初次创建时立即触发一次,而不是等待数据变化

    示例:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    18.5 生命周期函数

    请添加图片描述

    示例:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    18.6 父子间通信

    父组件通过props向子组件传递数据,子组件通过事件向父组件发送消息。

    • Props:父组件通过属性的方式传递数据给子组件。子组件通过定义props接收这些数据。
    • Events:子组件使用$emit触发事件,父组件通过监听这些事件来响应子组件的行为。

    父组件:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    子组件:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    18.7 模板引用

    模板引用(template refs)允许直接访问DOM元素或组件实例。这在需要直接操作DOM或访问组件的特定方法时非常有用。

    用法:

    可以使用ref属性在模板中创建一个引用。这个属性的值应该是一个字符串,表示引用的名称。然后,可以在JavaScript部分通过ref API访问这个元素。

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    注意事项:

    • 访问时机:只有在Vue组件挂载(mounted)后,模板引用才会被填充。因此,在onMounted钩子中访问模板引用是安全的。
    • 响应式:虽然模板引用本身不是响应式的,但通过.value访问的DOM元素是实时的,意味着它总是指向当前的DOM元素或组件实例。

    18.8 provide和inject

    provideinject 它们允许跨组件树传递数据,非常适合用于深层嵌套组件或需要共享数据的场景,而不必通过每个组件层手动传递 props。

    provide 选项允许一个组件向其所有子孙组件提供数据或方法,而无需通过每个单独的组件手动传递。你可以在任何组件中使用 provide 选项来定义数据或方法,然后在组件的任何后代中使用 inject 来访问它。

    inject 选项用于在任何子组件中接收从祖先组件通过 provide 提供的数据或方法。

    父组件:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    子/孙组件:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    18.9 defineOptions

    defineOptions 是 Vue 3.2 在

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    18.10 defineExpose

    使用

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    20.2 Store解构

    为了从 store 中提取属性时保持其响应性,需要使用 storeToRefs()。它将为每一个响应式属性创建引用。当只使用 store 的状态而不调用任何 action 时,它会非常有用。

    <script setup>
    import { storeToRefs } from 'pinia'
    const store = useCounterStore()
    // `name` 和 `doubleCount` 是响应式的 ref
    // 同时通过插件添加的属性也会被提取为 ref
    // 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性
    const { name, doubleCount } = storeToRefs(store)
    // 作为 action 的 increment 可以直接解构
    const { increment } = store
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    20.3 State

    在 Pinia 中,state 被定义为一个返回初始状态的函数。

    import { defineStore } from 'pinia'
    
    const useStore = defineStore('storeId', {
      // 为了完整类型推理,推荐使用箭头函数
      state: () => {
        return {
          // 所有这些属性都将自动推断出它们的类型
          count: 0,
          name: 'Eduardo',
          isAdmin: true,
          items: [],
          hasChanged: true,
        }
      },
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    20.4 Getter

    Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore() 中的 getters 属性来定义它们。推荐使用箭头函数,并且它将接收 state 作为第一个参数。

    export const useCounterStore = defineStore('counter', {
      state: () => ({
        count: 0,
      }),
      getters: {
        doubleCount: (state) => state.count * 2,
      },
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    export const useUserListStore = defineStore('userList', {
      getters: {
        getUserById: (state) => {
          return (userId) => state.users.find((user) => user.id === userId)
        },
      },
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    20.5 Action

    Action 相当于组件中的 method。它们可以通过 defineStore() 中的 actions 属性来定义,并且它们也是定义业务逻辑的完美选择。

    类似 getter,action 也可通过 this 访问整个 store 实例,不同的是,action 可以是异步的,可以在它们里面 await 调用任何 API,以及其他 action。

    export const useCounterStore = defineStore('main', {
      state: () => ({
        count: 0,
      }),
      actions: {
        increment() {
          this.count++
        },
        randomizeCounter() {
          this.count = Math.round(100 * Math.random())
        },
      },
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    const api = mande('/api/users')
    
    export const useUsers = defineStore('users', {
      state: () => ({
        userData: null,
        // ...
      }),
    
      actions: {
        async registerUser(login, password) {
          try {
            this.userData = await api.post({ login, password })
          } catch (error) {
            return error
          }
        },
      },
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    20.6 持久化

    持久化是指将应用状态保存在用户的浏览器中,即使在浏览器刷新或关闭后,状态也能被保留。

    要在 Pinia 中实现状态的持久化,可以使用第三方插件 pinia-plugin-persist。这个插件允许状态自动保存到浏览器的存储系统中,并在应用加载时重新加载这些状态。

    使用步骤:

    1)安装插件

    npm install pinia-plugin-persist
    
    • 1

    2)创建 Pinia Store

    // store.js
    import { defineStore } from 'pinia'
    
    export const useMainStore = defineStore('main', {
      state: () => ({
        counter: 0
      }),
      actions: {
        increment() {
          this.counter++;
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3)启用持久化

    在store 中启用持久化。可以选择哪些状态需要被持久化,以及使用哪种存储方式(例如 localStorage 或 sessionStorage)。

    // store.js
    import { defineStore } from "pinia";
    
    export const useMainStore = defineStore("main", {
      state: () => {
        return {
          counter: 0,
        };
      },
      actions: {
        increment() {
          this.counter++;
        },
      },
      persist: {
        enabled: true,
        strategies: [
          {
            key: "my-main-store",
            storage: localStorage, // 或者 sessionStorage
          },
        ],
      },
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    4)在 Vue 应用中使用 Pinia 和持久化插件

    在 Vue 应用入口文件中,安装 Pinia 并确保持久化插件被正确加载。

    import { createApp } from 'vue'
    import { createPinia } from 'pinia'
    import PiniaPersist from "pinia-plugin-persist";
    import './style.css'
    import App from './App.vue'
    const pinia = createPinia()
    pinia.use(PiniaPersist);
    createApp(App).use(pinia).mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    如何使用 Junit + Mockito 实践单元测试
    「随笔」前端面试 | 2022年前端面试基础必备
    Kotlin 协程调度切换线程是时候解开真相了
    Maven私服Docker的搭建
    正在等待操作系统重新启动。 请重新启动计算机以安装autocad 2024。
    儿童护眼哪个牌子好?精选双十一必买的儿童护眼灯品牌
    看着2022年世界杯,我无比怀念98世界杯
    vscode使用插件KoroFileHeader添加注释
    创建对象四种方式JAVA
    解决样本不均衡问题
  • 原文地址:https://blog.csdn.net/weixin_74144099/article/details/138158636