兵哥vue3

一、Vue3启程

1. 初始Vue3

   

姓名:{{name}}

   

年龄:{{age}}

   

// Vue2中--创建实例的方式

new Vue({

    //指定挂载容器

    // el:'#app',

    //定义属性

    data() {

        return {

            name:'张三',

            age:20

        }

    },

    //定义方法

    methods: {

        updateData(){

            this.name = '李四'

            this.age = 25

        }

    },

}).$mount('#app')  //指定当前vue实例挂载的容器

// Vue3中--创建实例的方式

Vue.createApp({

    //注意:这个配置对象里面除了不能写el选项,之前怎么写,现在还可以怎么写

    //定义属性

    data() {

        return {

            name:'张三',

            age:20

        }

    },

    //定义方法

    methods: {

        updateData(){

            this.name = '李四'

            this.age = 25

        }

    },

}).mount('#app')   //只能通过mount方法指定挂载的容器,不用通过el选项指定

2. Vue2和Vue3的响应式

   

学生:{{stu}}

   

食物:{{foods}}

   

       

       

       

       

   

// Vue2

new Vue({

    data() {

        return {

            //学生对象

            stu:{

                name:'张三',

                age:20

            },

            //食物数组

            foods:['榴莲','葡萄','香蕉']

        }

    },

    methods: {

        updateStuName(){

            this.stu.name = '李四'

        },

        addStuSex(){

            // 直接给对象添加的属性,不具备响应式

            // this.stu.sex = '男'

            // 如果要给对象添加属性,并且添加的属性也要具备响应式,要使用$set方法

            // 方法的第一个参数是指定的对象,第二个参数是属性名,第三个参数是属性值。

            this.$set(this.stu,'sex','男')

        },

        delStuAge(){

            // 直接删除对象身上的属性,是不具备响应式的

            // delete this.stu.age

            // 如果要删除对象身上的属性,并且还要具备响应式,要使用$delete方法

            // 方法的第一个参数是指定的对象,第二个参数是属性名

            this.$delete(this.stu,'age')

        },

        updateFoods2(){

            // 直接根据索引修改数组元素,不具备响应式

            // this.foods[1] = '西瓜'

            // 操作数组中的元素,并且还要具备响应式,只能使用数组的以下方法:

            // push unshift pop shift splice reverse sort

            // this.foods.splice(1,1,'西瓜')

            // 如果就是想通过下标去操作数组,还要具备响应式,使用$set方法

            this.$set(this.foods,1,'西瓜')

        }

    },

}).$mount('#app')

// 总结Vue2的响应式:不能直接给对象添加属性,删除对象的属性,不能直接操作数组的下标,

// 但是,Vue2同时也提供了解决这些问题的方案。

// Vue3

Vue.createApp({

    data() {

        return {

            //学生对象

            stu:{

                name:'张三',

                age:20

            },

            //食物数组

            foods:['榴莲','葡萄','香蕉']

        }

    },

    methods: {

        updateStuName(){

            this.stu.name = '李四'

        },

        addStuSex(){

            // 在Vue3中,直接给对象添加属性,新的属性依然具备响应式

            this.stu.sex = '男'

        },

        delStuAge(){

            // 在Vue3中,直接删除对象的属性,依然具备响应式

            delete this.stu.age

        },

        updateFoods2(){

            // 在Vue3中,根据下标操作数组,依然具备响应式

            this.foods[1] = '西瓜'

        }

    },

}).mount('#app')

// 总结Vue3的响应式:解决了再Vue2中的所有问题。

3. Vue2和Vue3的响应式原理

// Vue2的响应式原理:

// 这里的obj是源对象

let obj = {

    name:'张三',

    age:20

}

// 在页面中显示姓名和年龄

document.getElementById('name').innerText = obj.name

document.getElementById('age').innerText = obj.age

// 这里的obj2代理对象---由obj2代理obj

let obj2 = {}

// 给obj2定义name属性

Object.defineProperty(obj2,'name',{

    get(){

        return obj.name

    },

    set(value){

        obj.name = value

        document.getElementById('name').innerText = obj.name

    }

})

// 给obj2定义age属性

Object.defineProperty(obj2,'age',{

    get(){

        return obj.age

    },

    set(value){

        obj.age = value

        document.getElementById('age').innerText = obj.age

    }

})

// Vue3的响应式原理:

// 这里的obj是源对象

let obj = {

    name:'张三',

    age:20

}

// 在页面中显示姓名和年龄

document.getElementById('name').innerText = obj.name

document.getElementById('age').innerText = obj.age

// 这里的obj2代理对象---由obj2代理obj

// new Proxy(源对象,{...})的方式,创建代理对象

let obj2 = new Proxy(obj,{

    //读取属性,参数分别是:源对象,属性名

    get(target, property){

        // 直接根据源对象返回源对象身上的属性

        // return target[property]

        // 通过发射对象,发射输出源对象身上的属性

        return Reflect.get(target,property)

    },

    //设置属性,参数分别是:源对象,属性名,属性值

    set(target, property,value){

        // target[property] = value

        if(Reflect.has(target,property)){

            Reflect.set(target, property,value)

            document.getElementById(`${property}`).innerText = value

        }

    },

    //删除属性,参数分别是:源对象,属性名

    deleteProperty(target, property){

        // delete target[property]

        Reflect.deleteProperty(target, property)

    }

})

4. 引出Vue3新推出的组合式API

   

       

学生信息

       

       

姓名:{{stuName}}

       

年龄:{{stuAge}}

       

   

   

       

汽车信息

       

车名:{{carName}}

       

车价:{{carPrice}}

       

   

   

       

手机信息

       

名称:{{phoneName}}

       

颜色:{{phoneColor}}

       

   

   

       

食物信息

       

名称:{{foodName}}

       

价格:{{foodPrice}}

       

   

// 什么是组合式API(Composition API),就是Vue推出的一些新的方法,这个方法在setup中使用

// 从Vue身上获取ref组合式API函数

let {ref} = Vue

Vue.createApp({

    // 注意:Vue2中,Vue实例的data选项可以是一个对象,也可以是一个方法,由方法返回一个对象

    // 但是,组件中data选项必须是一个方法。

    // Vue3中,无论是Vue实例,还是组件,data选项都必须是一个方法。

    // 我们之前习惯将所有的数据放在data选项中定义,所有的方法放在methods选项中定义,

    // 所有的计算属性放在computed选项中定义,所有的侦听器放在watch选项中定义,

    // 这样就会导致一个业务的代码会拆分到多个结构中去写,如果一个页面中要操作很多个业务,代码后期维护成本会很高。

    // 所以,Vue3引入了组合式API,简化之前繁琐的过程,将相同业务的代码靠在一起写。

    /* data: function () {

        return {

            //定义学生数据

            stuName: '张三',

            stuAge: '20',

            //汽车信息

            carName: '奔驰',

            carPrice: '50W',

            //手机信息

            phoneName: 'iphone',

            phoneColor: '白色',

            //食物信息

            foodName: '汉堡',

            foodPrice: '¥20'

        }

    },

    methods: {

        //修改学生的方法

        updateStu(){

            this.stuName = '李四'

            this.stuAge = 30

        },

        //修改汽车的方法

        updateCar(){

            this.carName = '宝马'

            this.carPrice = '40W'

        },

        //修改手机的方法

        updatePhone(){

            this.phoneName = '华为'

            this.phoneColor = '蓝色'

        },

        updateFood(){

            this.foodName = '蛋糕'

            this.foodPrice = '¥30'

        }

    }, */

    // setup方法是所有组合式API的入口

    setup() {

        // 定义学生的信息

        // 在setup中,直接定义的数据是不具备响应式的,

        // 如果要使数据具备响应式,需要使用ref组合式API对数据进行包装,包装后返回的是ref对象

        let stuName = ref('张三')

        let stuAge = ref('20')

        let updateStu = () => {

            //ref对象的value属性保存的是值

            stuName.value = '李四'

            stuAge.value = 30

        }

        // 定义汽车的信息

        let carName = ref('奔驰')

        let carPrice = ref('50W')

        let updateCar = () => {

            carName.value = '宝马'

            carPrice.value = '40W'

        }

        // 定义手机的信息

        let phoneName = ref('iphone')

        let phoneColor = ref('白色')

        let updatePhone = () => {

            phoneName.value = '华为'

            phoneColor.value = '蓝色'

        }

        // 定义食物的信息

        let foodName = ref('汉堡')

        let foodPrice = ref('¥20')

        let updateFood = () => {

            foodName.value = '蛋糕'

            foodPrice.value = '¥30'

        }

        //返回模板中需要使用的数据

        return{

            stuName,

            stuAge,

            updateStu,

            carName,

            carPrice,

            updateCar,

            phoneName,

            phoneColor,

            updatePhone,

            foodName,

            foodPrice,

            updateFood

        }

    }

}).mount('#app')

5. ref和reactive

   

姓名:{{name}}

   

学生:{{stu}}

   

   

let {ref,reactive} = Vue

Vue.createApp({

    setup() {

        let name = ref('张三')

        let updateName = ()=>{

            name.value = '张杰'

        }

        /* let stu = ref({

            name:'李四',

            age:20

        })

        let updateStu = ()=>{

            // 注意:修改ref对象的值,每次都要先点value

            stu.value.name = '李明'

            stu.value.age = 30

        } */

        // reactive组合式API方法,根据源对象返回一个代理对象(Proxy对象)

        let stu = reactive({

            name:'李四',

            age:20

        })

        let updateStu = ()=>{

            // Proxy对象,不需要先点value

            stu.name = '李明'

            stu.age = 30

        }

        return {

            name,

            updateName,

            stu,

            updateStu

        }

    }

}).mount('#app')

二、脚手架

1. Vue-Cli

Vue CLI 4.x以上,Node.js版本 8.9以上

npm install -g @vue/cli

# OR

yarn global add @vue/cli

# 查看版本

vue --version

# 创建项目

vue create hello-world

# 运行

npm run serve

main.js

// vue2

/* import Vue from 'vue'

import App from './App.vue'

new Vue({

    render:h=>h(App)

}).$mount("#app") */

// vue3

// 从vue中导入createApp方法,通过这个方法,创建vue实例

import { createApp } from 'vue'

// 导入App组件

import App from './App.vue'

// 通过createApp方法创建一个vue实例,渲染App组件,并将结果挂载到#app容器中。

createApp(App).mount('#app')

2. Vite

Vite 需要 Node.js版本 12.0以上

npm init @vitejs/app

# OR

yarn create @vitejs/app

# 然后按照提示操作即可

# 安装依赖

npm install

# 运行

npm run dev

3. 计算属性

计算属性

姓:名:

姓名:{{fullName}}

// 在Vue3中,定义计算属性,需要引入computed组合式API

import {ref,computed} from 'vue'

export default {

    // Vue2中的计算属性

    // 数据

    /* data() {

        return {

            firstName:'张',

            lastName:'杰'

        }

    },

    // 计算属性

    computed:{

        // 只读的计算属性

        // fullName(){

        //     return this.firstName+'.'+this.lastName

        // }

        // 读写计算属性

        fullName:{

            //返回计算机属性的结果

            get(){

                return this.firstName+'.'+this.lastName

            },

            //修改计算属性的值

            set(val){

                let arr = val.split('.')

                this.firstName = arr[0]

                this.lastName = arr[1]

            }

        }

    } */

    // Vue3中的计算属性

    setup() {

        let firstName = ref('张')

        let lastName = ref('杰')

        //computed()函数的参数是一个回调函数,回调函数的返回值,就是计算属性的返回值

        // 定义只读的计算属性

        // let fullName = computed(()=>{

        //     return firstName.value + '.' + lastName.value

        // })

        // 定义读写计算属性

        let fullName = computed({

            get(){

                return firstName.value + '.' + lastName.value

            },

            set(val){

                let arr = val.split('.')

                firstName.value = arr[0]

                lastName.value = arr[1]

            }

        })

        return{

            firstName,

            lastName,

            fullName

        }

    }

};

4. 侦听器

侦听器

薪资:{{money}}

   

学生:{{stu}}

   

   

// 引入组合式API watch 和 watchEffect

import {ref,reactive, watch, watchEffect} from 'vue'

export default {

    // Vue2中的侦听器

    /* //数据

    data() {

        return {

            money:10000,

            stu:{

                name:'张三',

                age:20,

                car:{

                    name:'奔驰',

                    price:50

                }

            }

        }

    },

    //侦听器

    watch:{

        //根据数据的名称定义一个方法,用于该方法去侦听该属性值是否发生变化(参数1是新值,参数2是旧值)

        // 注意:默认情况下,侦听器一上来不会立刻执行,必须要侦听到值重新发生变化后,才执行。

        // money(nval,oval){

        //     console.log(nval,oval);

        // }

        // 完整写法,侦听器定义成一个对象

        money:{

            //表示侦听器默认执行一次

            immediate:true,

            //定义侦听器的方法

            handler(nval,oval){

                console.log(nval,oval);

            }

        },

        // 监听学生数据,注意:只有整个学生对象变化了才会监听到,如果只是修改对象身上的属性,监听不到。

        // stu(nval,oval){

        //     console.log(nval,oval);

        // }

        // 解决方案:监听器改成一个对象

        stu:{

            //表示侦听器开启深度监视

            deep:true,

            handler(nval,oval){

                console.log(nval,oval);

            }

        }

    } */

    // Vue3中的侦听器

    setup() {

        let money = ref(10000)

        let stu = reactive({

            name:'张三',

            age:20,

            car:{

                name:'奔驰',

                price:50

            }

        })

        // watch函数有三个参数:1.侦听谁,2.回调函数,3.配置对象(可以省略)

        // 简单用法:一上来没有立刻执行

        // watch(money,(nval,oval)=>{

        //     console.log(nval,oval);

        // })

        // 完整用法:加上第三个参数,配置对象

        watch(money,(nval,oval)=>{

            console.log(nval,oval);

        },{

            //立刻执行

            immediate:true,

        })

        // 监视reactive的数据,默认就开启深度监视,并且无法关闭

        // watch(stu,(nval,oval)=>{

        //     console.log(nval,oval);

        // })

        // 对于reactive的数据,可以采用监视部分属性

        watch(()=>stu.name,(nval,oval)=>{

            console.log(nval,oval);

        })

        // 如果监视的是reactive里面的对象属性,默认是不开启深度监视的,需要手动开启

        watch(()=>stu.car,(nval,oval)=>{

            console.log(nval,oval);

        },{

            deep:true

        })

        //watchEffect监听器,只有一个回调函数参数,并且没有参数

        // 特点:

        // 1.默认会执行一次

        // 2.不需要明确监视谁,回调函数里面用到了谁,谁变了,就会重新执行回调函数。

        watchEffect(()=>{

            console.log('我是watchEffect');

            let m = money.value

             let name = stu.name

        })

        return{

            money,

            stu

        }

    }

};

5. 过滤器

过滤器

薪资:{{toFixed2(money)}}

薪资:{{toFixed2Money}}

export default {

    data() {

        return {

            money:10000.12345

        }

    },

    // 注意:在Vue2中可以定义过滤器,但是在Vue3中已经取消了过滤器。

    /* filters:{

        toFixed2(val){

            return val.toFixed(2)

        }

    } */

    // Vue3推荐我们使用方法 或 计算属性的方式,实现之前过滤器的效果。

    methods: {

        toFixed2(val){

            return val.toFixed(2)

        }

    },

    computed:{

        toFixed2Money(){

            return this.money.toFixed(2)

        }

    }

};

6. 响应式

响应式

薪资:{{money}}

汽车:{{car}}

学生:{{stu}}

//Vue3中的所有组合式API,都要采用按需引入的方式导入

import {ref,reactive} from 'vue'

export default {

    //setup是所有组合式API的入口

    setup() {

        //使用ref定义基本类型数据

        let money = ref(10000)

        let updateMoney = ()=>{

            money.value += 1000

        }

        //使用ref定义引用类型数据

        // ref方法,返回的是ref对象,ref对象的value属性是一个代理对象(Proxy)

        let car = ref({

            name:'奔驰',

            price:'50W'

        })

        let updateCar = ()=>{

            // 注意:这里每次修改数据时,必须要先.value再.具体的属性

            car.value.name = '宝马',

            car.value.price = '40W'

        }

        // 注意:reactive只能定义引用类型(对象和数组)

        // reactive方法,直接返回一个代理对象(Proxy)

        let stu = reactive({

            name:'张三',

            age:20

        })

        let updateStu = ()=>{

            stu.name = '李四'

            stu.age = 25

        }

        // 总结:通常情况下:

        // 1.基本类型的数据,选择用ref定义

        // 2.引用类型的数据,选择用reactive定义


        //setup方法里面返回出去的成员,在模板可以使用

        return{

           money,

           updateMoney,

           car,

           updateCar,

           stu,

           updateStu

        }

    }

}

7. fragment组件

在vue3的模板中,不再需要根标签,它内部有一个fragment的组件作为模板的根标签

三、Vue3高阶

1. Hook函数

useCar

import {ref,computed} from 'vue'

//导出去一个函数

export default function(){

    //汽车数据

    let carName = ref('保时捷')

    let carPrice = ref(100)

    //汽车的计算属性

    let carPrice2 = computed(()=>{

        return (carPrice.value*0.8).toFixed(2)

    })

    //操作汽车的方法

    let updateCar = ()=>{

        carName.value = '宾利'

        carPrice.value = 300

    }

    //返回暴露给外界的内容

    return {

        carName,

        carPrice,

        carPrice2,

        updateCar

    }

}

usePhone

import {ref,computed} from 'vue'

export default function(){

    //手机数据

    let phoneName = ref('华为')

    let phonePrice = ref(5000)

    //手机的计算属性

    let phonePrice2 = computed(()=>{

        return (phonePrice.value*0.5).toFixed(2)

    })

    //操作手机的方法

    let updatePhone = ()=>{

        phoneName.value = '苹果'

        phonePrice.value = 9000

    }

    //返回暴露给外界的内容

    return {

        phoneName,

        phonePrice,

        phonePrice2,

        updatePhone

    }

}

组件

Hook函数

   

汽车信息

   

           

  • 汽车名称:{{carName}}
  •        

  • 汽车价格:{{carPrice}}万
  •        

  • 优惠价格:{{carPrice2}}万
  •        

  •            

           

  •    

   

手机信息

   

           

  • 手机名称:{{phoneName}}
  •        

  • 手机价格:{{phonePrice}}
  •        

  • 优惠价格:{{phonePrice2}}
  •        

  •            

           

  •    

// 导入hook函数

import useCar from '../hooks/useCar'

import usePhone from '../hooks/usePhone'

export default {

    setup() {

        // 返回模板中需要使用的数据

        return {

            //返回汽车信息

            ...useCar(),

            //返回手机信息

            ...usePhone()

        }

    }

}

2. 生命周期

生命周期

    数量:{{count}}

       

// 组合式API生命周期函数

import {onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'

export default {

    // beforeCreate() {

    //     console.log('创建之前');

    // },

    // created() {

    //     console.log('创建完成');

    // },

    // beforeMount() {

    //     console.log('挂载之前1');

    // },

    // mounted() {

    //     console.log('挂载完成1');

    // },

    // beforeUpdate() {

    //     console.log('更新之前1');

    // },

    // updated() {

    //     console.log('更新完成1');

    // },

    //注意:在vue3中,对beforeDestroy和destroyed这两个生命周期函数,进行了重命名

    /* beforeDestroy() {

        console.log('销毁之前');

    },

    destroyed() {

        console.log('销毁完成');    

    }, */

    // 在vue3中,beforeUnmount 替换了 beforeDestroy;unmounted 替换了 destroyed

    // beforeUnmount() {

    //     console.log('卸载之前1');

    // },

    // unmounted() {

    //     console.log('卸载完成1');

    // },

    data() {

        return {

            count:1

        }

    },

    // setup()函数,可以替代beforeCreate 和 created 这两个生命周期函数

    setup() {

        console.log('setup');

        //组合式API生命周期函数,会先与传统的生命周期函数执行

        onBeforeMount(()=>{

            console.log('挂载之前2');

        })

        onMounted(()=>{

            console.log('挂载完成2');

        })

        onBeforeUpdate(()=>{

            console.log('修改之前2');

        })

        onUpdated(()=>{

            console.log('修改完成2');

        })

        onBeforeUnmount(()=>{

            console.log('卸载之前2');

        })

        onUnmounted(()=>{

            console.log('卸载完成2');

        })

    }

}

3. toRef和toRefs

toRef和toRefs

   

学生信息

   

           

  • 姓名:{{name}}
  •        

  • 姓名:{{age}}
  •        

  • 车名:{{car.name}}
  •        

  • 车价:{{car.price}}
  •    

import { reactive,toRef,toRefs } from 'vue'

export default {

    setup() {

        // 定义数据

        let stuData = reactive({

            name:'张三',

            age:20,

            car:{

                name:'大众',

                price:'20W'

            }

        })

        return{

            // toRef()函数,可以用来为一个 reactive 对象的属性创建一个 ref

            // 这样做的好处是,简化了模板中的表达式。

            // toRef()函数,需要传两个参数:1.reactive 对象,2.具体的属性名

            // name:toRef(stuData,'name'),

            // age:toRef(stuData,'age'),

            // car:toRef(stuData,'car')

            // 假如 reactive 对象中,有100个属性,上面的操作要写100次,所以,一般都直接用toRefs函数

            // toRefs函数,把一个响应式对象转换成普通对象,该普通对象的每个 属性 都是一个 ref

            ...toRefs(stuData)

        }

    }

}

4. 其他的组合式API

其他的组合式API

    学生信息:{{stuData}}

   

   

   

    num3的值:{{num3}}

    汽车信息:{{car}}

   

    手机信息:{{phone}}

   

    年龄:{{age}}

   

import {ref,reactive,readonly,isRef,unref, shallowRef, isReactive, shallowReactive,customRef,toRaw, markRaw} from 'vue'

export default {

    setup() {

        // 定义数据

        // readonly()函数,返回一份只读数据,这个只读是“深层的”,内部任何嵌套的属性也都是只读的

        let stuData = readonly({

            name:'张三',

            age:20,

            car:{

                name:'大众',

                price:20

            }

        })

        let num1 = ref(100)

        let num2 = 200

        // isRef()函数,检查一个值是否为一个 ref 对象

        // isProxy()函数,检查一个对象是否是由 reactive 或者 readonly 方法创建的代理

        // isReactive()函数,检查一个对象是否是由 reactive 创建的响应式代理

        // isReadonly()函数,检查一个对象是否是由 readonly 创建的只读代理

        // let num3 = (isRef(num1)?num1.value:num1) + (isRef(num2)?num2.value:num2)

        // unref()函数,如果参数是一个 ref 则返回它的 value,否则返回参数本身

        let num3 = unref(num1) + unref(num2)

        // ref() 返回的对象 value 属性值是 reactive对象(代理对象)

        // shallowRef() 返回的对象 value 属性值是 object对象(普通对象),不再具备任何响应式了

        let car = shallowRef({

            name:'大众',

            type:{

                typeName:'SUV'

            }

        })

        let updateCar = ()=>{

            // 由于value返回的是object对象,所以,这里不再具有响应式

            car.value.name = '奔驰'

            car.value.type.typeName = '跑车'

        }

        // shallowReactive() 返回一个浅层的响应式代理,只对对象的第一层属性创建响应式

        let phone = shallowReactive({

            name:'华为',

            type:{

                typeName:'滑盖手机'

            }

        })

        // toRaw() 将代理对象转为一个普通对象返回

        let phone2 = toRaw(phone)

        console.log(phone2);

        console.log('--------------------');

        //定义了一份数据

        // markRaw() 记一个对象为“永远不会转为响应式代理”

        let food = markRaw({

            name:'面包'

        })

        // 注意:food2就是一个普通对象

        let food2 = reactive(food)

        console.log(food2);

        let updatePhone = ()=>{

            //修改name,会触发页面更新

            // phone.name += "!"

            //修改type里面的属性,不会触发页面更新

            phone.type.typeName += "!"

        }

        //自定义一个ref

        function useDebouncedRef(value, delay = 200) {

            let timeout

            // customRef(),用于自定义一个 ref

            return customRef((track, trigger) => {

                return {

                    get() {

                        track()

                        return value

                    },

                    set(newValue) {

                        clearTimeout(timeout)

                            timeout = setTimeout(() => {

                            value = newValue

                            trigger()

                        }, delay)

                    },

                }

            })

        }

        let age = useDebouncedRef(20,2000)

        return {

            stuData,

            num3,

            car,

            updateCar,

            phone,

            updatePhone,

            age

        }

    }

}

四、组件传值

1. 父子组件传值

      @updateName="name=$event" @updateAge="age=$event" @updateSex="sex=$event">

   

   

   

   

Son1

    姓名:{{myName}}

    年龄:{{myAge}}

    性别:{{mySex}}

   

import { ref } from 'vue';

import GrandSon1 from './GrandSon1.vue'

export default {

  name: "Son1",

  components:{

      GrandSon1

  },

  // 接收父组件传过来的数据

  props:['name','age'],

  // Vue2中的方式  

  /* data() {

      return {

          myName:this.name,

          myAge:this.age,

          mySex:this.sex

      }

  },

  methods: {

      updateData(){

          this.myName = '李四'

          this.myAge = 30

          this.mySex = '女'

          this.$emit('updateName',this.myName)

          this.$emit('updateAge',this.myAge)

          this.$emit('updateSex',this.mySex)

      }

  }, */

  //setup函数中通过参数props接收父组件传递进来的参数

  //注意:props参数中,只会接收props选项中接收的参数

  //context参数里面有三个对象:attrs,emit,slots

  //attrs用于获取没有采用props选项接收的参数

  //emit用于触发自定义事件

  //slots用于获取插槽信息

  setup(props,{attrs,emit,slots}) {

      //slots对象返回的是插槽里面所有内容的虚拟DOM

      console.log(slots.one()[0].children);

      //获取姓名和年龄

      let myName = ref(props.name)

      let myAge = ref(props.age)

      //获取性别

      let mySex = ref(attrs.sex)

      //修改数据的方法

      let updateData = ()=>{

          //修改自身数据

          myName.value = '李四'

          myAge.value = 30,

          mySex.value = '女'

          //触发自定义事件,将最新数据回传给父组件

          emit('updateName',myName.value)

          emit('updateAge',myAge.value)

          emit('updateSex',mySex.value)

      }

      return{

          myName,

          myAge,

          mySex,

          updateData

      }

  }

};

2. 祖孙组件传值

import {reactive, provide} from 'vue'

let phone = reactive({

    name:'华为',

    price:5000

})

//provide将指定的数据添加为依赖数据,让后代组件可以直接使用

provide('phone',phone)

GrandSon1

    手机信息:{{phone}}

   

import {inject} from 'vue'

// inject注入祖级组件中设置为依赖的数据

let phone = inject('phone')

let updatePhone = ()=>{

    phone.name = '苹果'

    phone.price = 8000

}

return {

    phone,

    updatePhone,

}

3. v-model

@click="testClick" />

Son2

    姓名:{{myName}}

    年龄:{{myAge}}

    性别:{{mySex}}

   

   

let testClick = (e)=>{

    alert(e)

}

import { ref } from 'vue';

export default {

  name: "Son2",

  //props选项接收父组件参数

  props:['name','age','sex'],

  //emits选项确定父组件可以触发哪些事件

  //注意:因为click跟原生事件同名,如果不在emits里面配置的话,父组件会触发两次click事件

  emits:['click'],

  setup(props,{emit}) {

      let myName = ref(props.name)

      let myAge = ref(props.age)

      let mySex = ref(props.sex)

      let updateData = ()=>{

          myName.value = '谢娜'

          myAge.value = 35,

          mySex.value = '女'

          //注意:自定义事件名称必须命名为update:属性名

          //就可以实现对父组件中指定属性的双向绑定  

          emit('update:name',myName.value)

          emit('update:age',myAge.value)

          emit('update:sex',mySex.value)

      }

      let emitClick = ()=>{

          //触发一个click事件

          emit('click','哈哈')

      }

      return{

          myName,

          myAge,

          mySex,

          updateData,

          emitClick

      }

  }

};

4. 异步组件

定义

Son3

姓名:{{name}},年龄:{{age}}

import {ref} from 'vue'

export default {

  name: "Son3",

  setup() {

      let name = ref('周杰伦')

      let age = ref(20)

      //注意:通常情况下,setup方法直接返回对象,不要返回Promise对象。

      return new Promise((resolve,reject)=>{

          setTimeout(() => {

            resolve({

                name,

                age

            })

          }, 2000);

      })

  }

使用

   

   

// defineAsyncComponent组合式API,用于定义异步组件

import {defineAsyncComponent} from 'vue'

// 异步导入组件

let Son3 = defineAsyncComponent(()=>import('./components/Son3.vue'))

5. teleport组件

Son4

   

       

   

五、vuex4 & vue-router4

1. 创建router对象

// createRouter方法,用于创建路由器对象

// createWebHashHistory方法,用于生成hash模式的路由,路由地址中包含一个#

// createWebHistory方法,用于生成history模式的路由

import {createRouter,createWebHashHistory} from 'vue-router'

// 创建当前项目中的路由器对象

let router = createRouter({

    //定义路由模式

    history:createWebHashHistory(),

    //定义具体的路由信息

    routes:[

        //每一条路由信息,配置一个对象

        {

            path:'/',

            name:'home',

            component:()=>import('../views/Home.vue')

        },

        {

            path:'/store',

            name:'store',

            component:()=>import('../views/Store.vue')

        },

        {

            path:'/list/:id',

            props:true,

            name:'list',

            component:()=>import('../views/List.vue')

        },

        {

            path:'/news',

            name:'news',

            component:()=>import('../views/News.vue')

        },

        {

            path:'/page1',

            name:'page1',

            component:()=>import('../views/Page1.vue')

        },

        {

            // 注意:不可以写通配符*

            // path:'*',

            path:'/:pathMatch(.*)*',

            name:'error404',

            component:()=>import('../views/Error404.vue')

        }

    ]

})

export default router

2. 使用router

//useRouter方法,返回当前项目中的路由器对象

//useRoute方法,返回当前路由信息对象

import {useRouter,useRoute} from 'vue-router'

//返回当前项目中的路由器对象

let $router = useRouter()

//获取当前路由信息

let $route = useRoute()

//通过props,也能获取都路由参数

props:['id']

//监听路由参数id

watch(()=>$route.params.id,(nval)=>{

    //清空数组

    showList.splice(0)

    //向数组中添加最新的数据

    showList.push(...list.filter(r=>r.typeId==$route.params.id))

},{

    //一上来,先执行一次

    immediate:true

})

3. 创建store对象

// 从vuex中导入createStore方法,该方法,用于创建全局状态管理对象

import { createStore } from 'vuex'

// 导入汽车模块

import car from './modules/car.js'

// 创建一个全局状态管理对象

let store = createStore({

    //定义状态

    state:{

        firstName:'张',

        lastName:'三'

    },

    //定义围绕状态的计算属性

    getters:{

        fullName(state){

            return state.firstName+'.'+state.lastName

        }

    },

    //定义同步方法

    mutations:{

        updateFirstName(state,val){

            state.firstName = val

        },

        updateLastName(state,val){

            state.lastName = val

        }

    },

    //定义异步方法

    actions:{

        updateFirstName(store,val){

            setTimeout(() => {

                store.commit('updateFirstName',val)

            }, 1000);

        },

        updateLastName(store,val){

            setTimeout(() => {

                store.commit('updateLastName',val)

            }, 1000);

        }

    },

    //模块

    modules:{

       car

    }

})

//导出全局状态管理对象

export default store

4. 使用store

//useStore方法,返回当前项目中的全局状态管理对象

import { useStore } from "vuex";

// 获取全局状态管理对象

let $store = useStore();

let firstName = computed(() => {

    return $store.state.firstName;

});

let lastName = computed(() => {

    return $store.state.lastName;

});

let fullName = computed(() => {

    return $store.getters.fullName;

});

let carName = computed(() => {

    return $store.state.car.carName;

});

let address = computed(() => {

    return $store.state.car.address;

});

let carInfo = computed(() => {

    return $store.getters["car/carInfo"];

});

function updateFirstName() {

    //调用mutations里面的方法,修改姓

    $store.commit("updateFirstName", "李");

}

function updateLastName() {

    //调用actions里面的方法,修改名

    $store.dispatch("updateLastName", "四");

}

function updateCarName() {

    //调用mutations里面的方法,修改车名

    $store.commit("car/updateCarName", "宾利");

}

function updateCarAddress() {

    //调用actions里面的方法,修改地址

    $store.dispatch("car/updateCarAddress", "英国");

}

5. 注册

// 导入当前项目中创建的全局状态管理对象

import store from './store'

// 导入当前项目中创建的路由器对象

import router from './router'

// 使用createApp方法创建一个Vue实例,该方法的参数是App组件,表示渲染App组件

// use方法,用于给当前vue实例添加功能

// mount方法,用于将渲染后的内容,挂载到指定的容器中

createApp(App).use(store).use(router).mount('#app')

你可能感兴趣的:(兵哥vue3)