• Vue3速成


    day 1

    1. 创建vue3工程

    相关代码如下:

    ## 创建vue工程
    npm create vue@lastest
    
    ## 安装node_modules
    npm install // npm i
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    创建工程完毕之后,进入文件夹可以发现有如下文件,下图是文件介绍:

    入口文件介绍:

    这里main.ts是与index.html建立联系的;

    通过.mount('#app')这样 main.ts就与index.html建立起了联系;

    其中main.ts的代码格式如下:

    <template>
        <div>
            <h1>你好</h1>
        </div>
    </template>
    
    <script setup lang="ts">
        // js或者ts
    </script>
    
    <style scoped>
        /* 样式 */
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    App.vue的代码格式如下:

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

    网页调试vue可以在chrome应用商店search vue.js devtools下载安装就好;

    你好

    ### 2. 选项式API和组合式API

    感觉vue2和vue3的主要不同就在于vue文件中script部分;其中vue2是选项式OptionsAPI的,vue3是组合式Composition的;

    选项式API相关代码如下

    注意,这里并没有setup

    
    
    • 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

    组合式相关代码如下

    注意,这里的setup比beforecreate执行得还要早,setup的返回值也可以是渲染函数,data,method,setup可以同时存在,setup不可以读取data中的数据,反之则可以,因为setup是执行得最早的;

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

    setup语法糖简化后代码如下:

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

    3. 响应式数据

    响应式数据创建有两种方法,一种是ref,一种是reactive

    ref定义基本类型的数据

    使用的相关代码如下:

    
    
    
    
    
    
    
    
    • 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

    reactive包起来后,对象变成了一个Proxy的对象,原对象在Proxy里面的target中;这里的reactive是深层次的,只能定义对象类型的响应式数据;

    refreactive的对比

    这里要注意的是,重新分配reactive的对象时,使用Object.assign,但是如果是利用ref定义的对象类数据,我们是可以直接进行替换的;

    对响应式数据进行解构,toReftoRefs

    let person = reactive({
    	name: '张三',
    	age: 18
    })
    
    let {name, age} = person
    // let name = person.name
    // let age = person.age
    
    let {name, age} = toRefs(person) //把reactive对象里面的每一组对象转化为ref
    // let name = toRef(person, 'name')
    // let age = toRef(person, 'age')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4. 计算属性

    v-bind 是 单向绑定,数据流向页面;v-model 是 双向绑定,页面也可以流向数据;

    计算属性 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    computed是用来区别于方法的,使用computed得到的属性是没有缓存的,而且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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    day 2

    5. watch 监视

    情况1:监视ref定义的基本类型数据

    停止监视只需要调用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
    • 36

    情况2:监视ref定义的对象类型数据

    这里要注意的是:若修改的是ref定义的对象中的属性,newVal和oldVal都是新值,因为是同一个对象;若修改的是ref定义的整个对象,newVal是新值,oldVal是旧值,因为不是同一个对象;

    
    
    
    
    
    
    
    
    • 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

    情况3:监视reactive定义的对象类型数据

    很简单,只需要把ref定义的对象改为reactive定义的对象,然后在修改整个对象的时候使用Object.assign替换就可以;

    
    
    
    
    
    
    
    
    • 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

    情况4:监视ref或者reactive定义的对象类型中的某个属性

    
    
    
    
    
    
    
    
    • 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

    情况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
    • 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

    6. watchEffect

    相较于watch,watchEffect不需要指定监视对象,而是响应式的追踪对象;

    
    
    
    
    
    
    
    
    • 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

    7. 标签的ref属性

    利用refdocument.getElementById('')的区别在于,前者是局部的,不会受到整体的干扰;

    
    
    
    
    
    
    
    
    • 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

    day 3

    8. 回顾TS中的接口_泛型_自定义类型

    一般在文件目录src下面有一个types文件夹,types中有一个index.ts文件可以直接导入(导入过程不需要写文件)

    这里文件表示泛型和接口的意思,一般是结合后端使用,避免缺失参数;

    // 定义一个接口,用于限制person对象的具体属性 string,number小写
    // 使用export暴露
    export interface PersonInter {
        id: string,
        name: string,
        // ?问号表示可有可无
        age?: number
    }
    
    
    // 一个自定义类型
    export type Persons = Array<PersonInter>
    // 也可以这样写 export type Persons = PersonInter[]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    
    
    
    
    
    
    
    
    • 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

    9. props的使用

    将父组件中的数据传给子组件

    vuehtml标签属性前面加冒号表示表达式

    <h2 a="1+1" :b="1+1">h2>
    
    • 1

    父组件如下:

    
    
    
    
    
    
    
    
    • 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

    子组件如下:

    
    
    
    
    
    
    
    
    • 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

    10. 生命周期

    组件的生命周期有四个阶段:创建,挂载,更新,销毁;

    钩子:生命周期函数 (阶段前,阶段完毕) 钩子一共有8个

    
    
    
    
    
    
    
    
    • 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

    11. 自定义Hooks

    Hooks是组合式功能的体现,其创建过程类似于8节中在文件目录src下创建一个hooks的文件夹,里面存放useXxxx.ts文件,实例如下:

    useAdd.ts

    import { computed } from '@vue/reactivity'
    import {ref, onMounted} from 'vue'
    
    export default function(){
        let sum = ref(0)
        let bigSum = computed(()=>{
            return sum.value * 10
        })
    
        function add(){
            sum.value += 1
        }
    
        onMounted(()=>{
            sum.value += 1 
        })
        return {sum, add, bigSum}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    useDog.ts

    import {reactive, onMounted} from 'vue'
    import axios from 'axios'
    
    export default function(){
        let dogList = reactive([
            'https://images.dog.ceo/breeds/pembroke/n02113023_4136.jpg'
        ])
        
        // axios 的 实例用法1
        /* function addDog(){
            axios.get('https://dog.ceo/api/breed/pembroke/images/random').then(
                response => {dogList.push(response.data.message)},
                error => {console.log(error)}
            )
        } */
    
        // axios 的 实例用法2
        async function addDog() {
            try {
                let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
                dogList.push(result.data.message)
            } catch (error) {
                console.log(error)
            }
        }
    
        onMounted(()=>{
            addDog()
        })
    
        return {dogList, addDog}
    }
    
    • 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

    这样组件中可以直接应用hooks文件下的内容:

    
    
    
    
    
    
    
    
    • 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

    一般在文件目录src下面有一个types文件夹,types中有一个index.ts文件可以直接导入(导入过程不需要写文件)

    12. 路由 基本切换效果

    路由和路由器不一样

    路由类似于键值对,route

    路由器类似于管理路由,router

    路由的创建与Hooks和TS接口类似,其创建过程类似于8节中在文件目录src下创建一个router的文件夹,里面存放index.ts文件(无需导入文件名),实例如下:

    index.ts 实例如下:

    // 创建一个路由器,并暴露出去
    
    
    // 第一步:引入createRouter
    import {createRouter, createWebHistory} from 'vue-router'
    
    // 第二步:引入可能要呈现的组件
    import Home from '@/components/Home.vue'
    import About from '@/components/About.vue'
    import News from '@/components/News.vue'
    
    
    // 第三步:创建路由器
    const router = createRouter({
        // history表示路由的工作模式
        history: createWebHistory(),
        routes:[// 一个个路由规则
            {
                path: '/home',
                component: Home
            },
            {
                path: '/news',
                component: News
            },
            {
                path: '/about',
                component: About
            }
        ]
    })
    
    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
    • 33

    在这里我们只是创建了路由,于此同时,我们需要把路由加载到项目中,所以接下来我们需要在main.ts文件中操作;

    // 引入createApp 用于创建应用
    import { createApp } from 'vue'
    // 引入app根组件
    import App from './App.vue'
    // 引入路由器
    import router from './router'
    // 创建一个应用
    const app = createApp(App)
    // 使用路由器
    app.use(router)
    // 挂载整个应用到app容器中
    app.mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    为了在App.vue引入组件,我们还需要做一些操作,使用RouterView, RouterLink

    
    
    
    
    
    
    
    
    • 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

    就完毕了,这里要用RouterLink替换a标签,并把href改成to,用RouterView表示component的插入位置;

    13. 路由 两个注意点

    路由组件一般放在pages或者views文件夹,一般组件通常放在components文件夹;

    通过点击导航,视觉上效果消失了的组件,默认是被销毁掉的,需要的时候再去挂载;

    14. 路由 路由器的工作模式

    路由器有两种工作模式,history和hash,前端一般用history,后端一般用hash;

    15. 路由 to的两种写法

    
    %% 第一种: %%
    <RouterLink to="/home" active-class="active">主页RouterLink>
    
    %% 第二种: %%:
    <RouterLink :to="{path='/home'}" active-class="active">主页RouterLink>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里再介绍一下 active-class ,由于RouterLink在渲染的时候会变成a标签,所以样式可以类似于设置如下:

    
        a.active {
            text-align: center;
            margin: 50px;
            color: red;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    16. 路由 命名路由

    可以在路由的index.ts文件中添加添加名字:

    // 创建一个路由器,并暴露出去
    
    
    // 第一步:引入createRouter
    import {createRouter, createWebHistory, createWebHashHistory} from 'vue-router'
    
    // 第二步:引入可能要呈现的组件
    import Home from '@/views/Home.vue'
    import About from '@/views/About.vue'
    import News from '@/views/News.vue'
    
    
    // 第三步:创建路由器
    const router = createRouter({
        // 路由的工作模式:history模式 不带#号 优先
        history: createWebHistory(),
        // 路由的工作模式:hash模式 带#号
        // history: createWebHashHistory(),
        routes:[// 一个个路由规则
            {
                name: 'zhuye',
                path: '/home',
                component: Home
            },
            {
                name: 'xinwen',
                path: '/news',
                component: News
            },
            {
                name: 'guanyu',
                path: '/about',
                component: About
            }
        ]
    })
    
    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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    17. 路由 嵌套路由

    子级不用加斜杠,但是to的时候需要完整的使用\news\detail

    // 创建一个路由器,并暴露出去
    
    // 第一步:引入createRouter
    import {createRouter, createWebHistory, createWebHashHistory} from 'vue-router'
    
    // 第二步:引入可能要呈现的组件
    import Home from '@/views/Home.vue'
    import About from '@/views/About.vue'
    import News from '@/views/News.vue'
    import Detail from '@/views/Detail.vue'
    
    // 第三步:创建路由器
    const router = createRouter({
        // 路由的工作模式:history模式 不带#号 优先
        history: createWebHistory(),
        // 路由的工作模式:hash模式 带#号
        // history: createWebHashHistory(),
        routes:[// 一个个路由规则
            {
                name: 'zhuye',
                path: '/home',
                component: Home
            },
            {
                name: 'xinwen',
                path: '/news',
                component: News,
                children:[
                    {
                        path: 'detail', //子级不用写斜杠
                        component: Detail,
                    }
                ]
            },
            {
                name: 'guanyu',
                path: '/about',
                component: About
            }
        ]
    })
    
    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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    18. 路由 query 参数

    在传参数给组件之前,我们需要给接收参数的组件添加一个Hooks:useRoute

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

    这里在RouterLink中添加query参数:

            <ul>
                <li v-for="news in NewsList" :key="news.id">
                    
                    { news.title }} -->
                    
                    <RouterLink :to="{
                        path: '/news/detail',
                        query: {
                            id: news.id,
                            title: news.title,
                            content: news.content
                        }
                    }">
                        {{ news.title }}
                    RouterLink>
    
                li>
            ul>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    19. 路由 params 参数

    首先需要在router中设置占位:就是在path中添加/:

    // 创建一个路由器,并暴露出去
    
    // 第一步:引入createRouter
    import {createRouter, createWebHistory, createWebHashHistory} from 'vue-router'
    
    // 第二步:引入可能要呈现的组件
    import Home from '@/views/Home.vue'
    import About from '@/views/About.vue'
    import News from '@/views/News.vue'
    import Detail from '@/views/Detail.vue'
    
    
    // 第三步:创建路由器
    const router = createRouter({
        // 路由的工作模式:history模式 不带#号 优先
        history: createWebHistory(),
        // 路由的工作模式:hash模式 带#号
        // history: createWebHashHistory(),
        routes:[// 一个个路由规则
            {
                name: 'zhuye',
                path: '/home',
                component: Home
            },
            {
                name: 'xinwen',
                path: '/news',
                component: News,
                children:[
                    {
                        name: 'xiangqing',
                        path: 'detail/:id/:title/:content?', // 需要占位 ?代表可传可不传
                        component: Detail,
                    }
                ]
            },
            {
                name: 'guanyu',
                path: '/about',
                component: About
            }
        ]
    })
    
    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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    params只能使用routename,而不能使用path,同时传参数只能使用基本类型,而不能使用数组和对象;

            <ul>
                <li v-for="news in NewsList" :key="news.id">
                    
                    { news.title }} -->
                    
                    <RouterLink :to="{
                        name: 'xiangqing',
                        params: {// 只能传基本类型,不能是对象和数组
                            id: news.id,
                            title: news.title,
                            content:news.content,
                        }
                    }">
                        {{ news.title }}
                    RouterLink>
    
                li>
            ul>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    20. 路由 props配置

    props:true 布尔值写法,只能搭配params使用,path需要占位

    props(route){return route.query} 函数式写法,其中route可以操作params和query

    props:{id:xx,title:xx,content:xx}

    其原理就相当于在 中 添加了

    21. 路由 replace属性

    类似于浏览器的前进后退机制;

        
    
    • 1
    • 2
    • 3
    • 4
    • 5

    直接在RouterLink后面添加replace,不会留下记录;

    22. 路由 编程式路由导航

    可以做到不点标签直接跳转的效果,脱离RouterLink实现跳转;router.push() router.replace() 括号中to能怎么写,括号就能怎么写;

    setTimeout(()=>{
    	// 在此处执行跳转
    }, 3000) // 3秒后执行函数
    
    • 1
    • 2
    • 3

    实例代码如下:

    import {onMounted} from 'vue'
    import { useRouter } from 'vue-router';
    
    const router = useRouter()
    
    onMounted(()=>{
    	setTimeout(()=>{
    		router.push('/news')
    	}, 3000)
    })
    
    • 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
    • 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

    23. 路由 重定向

    自动切换url,在router文件中补充规则:

    {
    	path: '/',
    	redirect: '/home'
    }
    
    • 1
    • 2
    • 3
    • 4

    day 4

    24. pinia 选项式写法

    pinia环境首先需要安装

    npm install pinia
    
    • 1

    安装之后,pinia的创建与Hooks和TS接口类似,其创建过程类似于8节中在文件目录src下创建一个store的文件夹,里面存放对应components中的文件实例如下:

    在main.ts文件中需要引入pinia

    import {createApp} from 'vue'
    import App from './App.vue'
    import {createPinia} from 'pinia'
    import router from './router'
    
    const app = createApp(App)
    const pinia = createPinia()
    
    app.use(pinia)
    app.use(router)
    
    app.mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Count.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
    • 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

    Count.ts 如下:

    import {defineStore} from 'pinia'
    import {ref} from 'vue'
    
    
    export const useCountStore = defineStore('Count', {
    	// 写函数
        actions:{
            increment(){
                this.sum += this.n
            }
        },
        // 真正存储数据的地方
        state(){
            return {
                sum: ref(0),
                n: ref(1),
            }
        },
        // 类似于vue中的computed属性
        getters:{
            bigSum: state=>state.sum*10,
            smallSum():number{
                return this.sum - 1000
            }
        }
    })
    
    • 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

    LoveTalk.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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    LoveTalk.ts如下:

    import {defineStore} from 'pinia'
    import {nanoid} from 'nanoid' // 生成id
    import axios from 'axios'
    
    export const useLoveStore = defineStore('LoveTalk', {
        actions:{
            async getTalk(){
                let {data:{content}} = await axios.get('https://api.uomg.com/api/rand.qinghua')
                let obj = {id: nanoid(), content: content}
                this.talkList.unshift(obj)
            }
        },
        // 真正存储数据的地方
        state(){
            return {
                talkList: JSON.parse(localStorage.getItem('talkList') as string ) || []
            }
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    25. pinia 组合式写法

    这里相对于选项式,我们需要把state中的部分转化为响应式才有效,然后添加return返回:

    LoveTalk.ts如下:

    import {defineStore} from 'pinia'
    import {nanoid} from 'nanoid'
    import axios from 'axios'
    import {reactive} from 'vue'
    
    export const useLoveStore = defineStore('LoveTalk', ()=>{
    
        // 这里写state中的部分
        let talkList = reactive(JSON.parse(localStorage.getItem('talkList') as string ) || [])
    
        async function getTalk(){
            console.log('获取一句')
            try {
                let {data:{content}} = await axios.get('https://api.uomg.com/api/rand.qinghua')
                let obj = {id: nanoid(), content: content}
                talkList.unshift(obj)
            } catch (error) {
                console.log('获取失败!')
            }
    
        }
    
        return {talkList, getTalk}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    day 5

    26. 组件通信_props

    Father.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
    • 36
    • 37
    • 38
    • 39
    • 40

    Child.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

    27. 组件通信_custom-event

    标签中使用@开头的props表示的是事件,比如@click是点击事件,如果我们需要打印事件,我们可以使用$event当做参数放入函数中获取事件;

    事件一般用串串的形式,而回调函数使用小驼峰

    Father.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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    Child.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

    28. 组件通信_mitt

    类似于总线bus,收数据的:在公共区域提前绑定好事件;提供数据的:在合适的时候触发事件;

    首先需要安装mitt

    npm i mitt
    
    • 1

    由于mitt属于一个工具,所以在src目录下创建一个utils文件夹,创建一个emitter.ts文件;

    emitter.ts 文件内容如下:

    // 引入 mitt
    import mitt from 'mitt'
    
    // 调用mitt得到emitter,emitter可以绑定事件和触发事件
    const emitter = mitt()
    
    // 绑定事件
    emitter.on('test1', ()=>{
        console.log('test1被调用了')
    })
    emitter.on('test2', ()=>{
        console.log('test2被调用了')
    })
    
    // 触发事件
    setInterval(()=>{
        emitter.emit('test1')
        emitter.emit('test2')
    }, 2000)
    
    // 解绑事件
    setTimeout(()=>{
        emitter.off('test1')
    
        // 全部解绑
        // emitter.all.clear()
    }, 3000)
    
    // 暴露emitter
    export default emitter
    
    • 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

    同时,需要在mian.ts文件中进行引入:

    import {createApp} from 'vue'
    import App from './App.vue'
    import {createPinia} from 'pinia'
    import router from './router'
    import emitter from './utils/emitter'
    
    const app = createApp(App)
    const pinia = createPinia()
    
    app.use(pinia)
    app.use(router)
    
    app.mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    注意,这里不需要app.use;

    Child1.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

    Child2.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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    29. 组件通信_v-model

    UI组件库底层大量使用v-model进行通信;

    e v e n t :对于原生事件, event: 对于原生事件, event:对于原生事件,event就是事件对象; 能==> .target
    对于自定义事件,$event就是触发事件时,所传递的数据; 不能==> .target

    Father.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
    • 36

    自定义组件MyCustomInput.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

    30. 组件通信_$attrs

    使用props,未用defineProps的数据,子组件会使用attrs接收;

    Father.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
    • 36
    • 37
    • 38

    Child.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

    Grandson.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

    31. 组件通信_$refs$parent

    $refs可以获取html下所有的ref组件,$parent可以获取父组件中的数据;都要结合defineExpose()

    Father.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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    Child1.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

    Child2.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

    32. 组件通信_provide-inject

    常用于祖孙之间越过父亲直接通信;

    祖使用provide传送,孙使用inject接收,inject第二个参数是默认值

    Father.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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    Child.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

    32. 组件通信_slot默认插槽

    slot有三种:默认插槽,具名插槽,作用域插槽;

    默认插槽就是在组件中间使用html标签,然后在组件中加入

    Father.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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    Child.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

    33. 组件通信_slot具名插槽

    具名插槽意思就是具有名字的插槽,这里默认插槽的名字为default,多个slot可以倒序;

    Category.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

    Father.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
    • 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

    34. 组件通信_slot作用域插槽

    主要用在子里面有数据,但是父组件想以不同形式进行表示;

    Game.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

    Father.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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    35. shallowRef 和 shallowReactive

    36. readonly 和 shallowReadonly

    37. toRaw 和 markRaw

    38. customRef

    customRef() 预期接收一个工厂函数作为参数,这个工厂函数接受 track 和 trigger 两个函数作为参数,并返回一个带有 get 和 set 方法的对象。

    一般来说,track() 应该在 get() 方法中调用,而 trigger() 应该在 set() 中调用。然而事实上,你对何时调用、是否应该调用他们有完全的控制权。

    示例 创建一个防抖 ref,即只在最近一次 set 调用后的一段固定间隔后再调用:

    import { customRef } from 'vue'
    
    export function useDebouncedRef(value, delay = 200) {
      let timeout
      return customRef((track, trigger) => {
        return {
    	  // 数据被读取时,调用get
          get() {
            track() // 告诉vue数据value很重要,一旦value变化就去更新
            return value
          },
          // 数据被修改时,调用set
          set(newValue) {
            clearTimeout(timeout)
            timeout = setTimeout(() => {
              value = newValue
              trigger() // 通知一下vue数据value变化了
            }, delay)
          }
        }
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    39. Teleport

    这个组件中有一个 

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

    40. Suspense

    在这个组件树中有多个嵌套组件,要渲染出它们,首先得解析一些异步资源。如果没有 ,则它们每个都需要处理自己的加载、报错和完成状态。在最坏的情况下,我们可能会在页面上看到三个旋转的加载态,在不同的时间显示出内容。

    有了  组件后,我们就可以在等待整个多层级组件树中的各个异步依赖获取结果时,在顶层展示出加载中或加载失败的状态。

     可以等待的异步依赖有两种:

    1. 带有异步 setup() 钩子的组件。这也包含了使用