vue3.x全家桶+vite(二)composition api

2021-12-15  本文已影响0人  感觉不错哦
Options API 和 Composition API 的对比

在vue2中,我们会在一个vue文件中methods,computed,watch,data中等等定义属性和方法,共同处理页面逻辑,我们称这种方式为Options API

缺点: 一个功能往往需要在不同的vue配置项中定义属性和方法,比较分散,项目小还好,清晰明了,但是项目大了后,一个methods中可能包含很多个方法,你往往分不清哪个方法对应着哪个功能

当然这种都是废话了,不过在vue3中还是可以使用vue2.x中的开发方式,就不演示了,主要演示一下Composition API

setup

插眼

不喜欢看文档或者不喜欢这个文档节奏的,直接看我的就行了,带你一步步使用各种api,开始小试牛刀

根据setup,Vue3.2以上推出了语法糖 <script setup></script>,其实学习晚点也是有好处的,黑科技都在后面

    <template>
        <div>
            <div>{{ number }}</div>
        </div>
    </template>
    <script>
    import { ref } from "vue";
    export default {
        setup(){
            return{
                number:ref(0)
            }
        }
    }
    </script>

再对比一下 <script setup></script>

    <template>
        <div>
            <div>{{ number }}</div>
        </div>
    </template>

    <script setup>
        import { ref } from "vue";
        let number = ref(0);
    </script>

再对比一下引入组件的方式

    <template>
        <div>
            home
            <Count></Count>
        </div>
    </template>
    <script setup>
      import Count from '../components/Count.vue'
    </script>

    <script>
      import Count from '../components/Count.vue'

    export default {
        components:{Count} 
    }
    </script>

对比一下相对来说<script setup></script>就十分简洁,composition api初使用还是很舒服的哈

那么setup函数还是有俩参数的,那么这个留到父子传值的时候再写仔细点,现在也用不上哈
新的响应式数据

Vue 中用过三种响应式解决方案,分别是 defineProperty、Proxy 和 value setter,但 defineProperty API 作为 Vue 2 实现响应式的原理,它的语法中也有一些缺陷。比如在配置代码中删除某属性,set 函数就不会执行,还是之前的数值。这也是为什么在 Vue 2 中,我们需要 $delete 一个专门的函数去删除数据(demo就不演示了,老玩家都知道哈,不知道赶紧先学vue2)。

Vue 3 的响应式机制是基于 Proxy 实现的,有个deleteProperty函数去管理各种操作哈,从而实现了响应式的功能,之前的文章有介绍,可以自己找一下

如何使用ref reactive toRefs

在Vue3.X中,使用ref 与reactive 来声明响应式变量,给大家演示一下

    <template>
        <div>
            <div>
                <button @click="add"> {{ number }}</button>
            </div>
        </div>
    </template>

    <script setup>
        import { ref } from "vue";
        let number = ref(0);
        const add = function(){
            number.value = ++ number.value
        }
    </script>

setup函数版,学习就要多敲

    <template>
        <div>
            <button @click="add">{{ number }}</button>
        </div>
    </template>
    <script>
    import { ref } from "vue";
    export default {
        setup() {
            let number = ref(0)
            const add = function () {
                number.value = ++number.value
            }
            return {
                number,
                add,
            }
        }
    }
    </script>

问题不大,++效果非常完美,就是页面比较丑,那不重要

    <template>
        <div>
            <button @click="add">{{ number }}</button>
            <div></div>
            {{ obj.name }}
            <button @click="changename">修改名字</button>
        </div>
    </template>

    <script setup>
        import { ref } from "vue";
        let number = ref(0);
        const add = function () {
            number.value = ++number.value
        }
        let obj = ref({
            name: 'lwj',
            age: '24'
        })
        
        const changename = function () {
        obj.value.name = 'test'
        }
    </script>

setup函数版

    <template>
        <div>
            <button @click="add">{{ number }}</button>
            
            <div></div>

            {{obj.name}}
            <button @click="changename"> 修改名字 </button>
        </div>
    </template>
    <script>
    import { ref } from "vue";
    export default {
        setup() {
            let number = ref(0)
            let obj = ref({
                name:'lwj',
                age:'24'
            })
            const add = function () {
                number.value = ++number.value
            }
            const changename = function(){
                obj.value.name = 'test'
            }
            return {
                number,
                add,
                obj,
                changename
            }
        }
    }
    </script>

可以成功修改哈,如果将对象分配为 ref 值,则它将被 reactive 函数处理为深层的响应式对象。相当于你还不如使用reactive,而且reactive不用使用.value去读取

    <template>
        <div>
            <button @click="add">{{ number }}</button>
            <div></div>
            {{ obj.name }}
            <button @click="changename">修改名字</button>
        </div>
    </template>

    <script setup>
        import { ref,reactive } from "vue";
        let number = ref(0);
        const add = function () {
            number.value = ++number.value
        }
        let obj = reactive({
            name: 'lwj',
            age: '24'
        })

        const changename = function () {
            obj.name = 'test'
        }
    </script>

setup函数版

    <template>
        <div>
            <button @click="add">{{ number }}</button>
            
            <div></div>

            {{obj.name}}
            <button @click="changename"> 修改名字 </button>
        </div>
    </template>
    <script>
    import { ref,reactive } from "vue";
    export default {
        setup() {
            let number = ref(0)
            let obj = reactive({
                name:'lwj',
                age:'24'
            })
            const add = function () {
                number.value = ++number.value
            }
            const changename = function(){
                obj.name = 'test'
            }
            return {
                number,
                add,
                obj,
                changename
            }
        }
    }
    </script>

有一点点简洁了吧,那写到这里,其实格式还不是很好,那么其实对象这种东西是可以储存任何数据的,我们可以把方法变量都使用reactive 不是很好

    <template>
        <div>
            <button @click="add">{{ obj.number }}</button>

            <div></div>
            {{ obj.name }}
            <button @click="changename">修改名字</button>
        </div>
    </template>
    <script>
    import { ref, reactive,toRefs } from "vue";
    export default {
        setup() {
            const obj = reactive({
                name: 'lwj',
                number: 0,
                add: () => {
                    //setup中 this改向了undefined
                    obj.number = ++obj.number
                },
                changename: () => {
                    obj.name = 'test'
                }
            })
            return {obj}    
        }
    }
    </script>

此处使用setup函数演示比较清楚哈,方法的话没有生效,因为数据没有响应,那我们引入toRef函数,可以使其响应

    <template>
        <div>
            <button @click="add">{{ number }}</button>

            <div></div>
            {{ name }}
            <button @click="changename">修改名字</button>
        </div>
    </template>
    <script>
    import { ref, reactive, toRefs, toRef } from "vue";
    export default {
        setup() {
            const obj = reactive({
                name: 'lwj',
                number: 0,
                add: () => {
                    //setup中 this改向了undefined
                    obj.number = ++obj.number
                },
                changename: () => {
                    obj.name = 'test'
                }
            })
            const name = toRef(obj, 'name')
            const number = toRef(obj, 'number')
            
            return { name, number }
        }
    }
    </script>

这样的话数据是响应了,但是方法没生效,因为我们没有将方法返回,

    <template>
        <div>
            <button @click="add">{{ number }}</button>

            <div></div>
            {{ name }}
            <button @click="changename">修改名字</button>
        </div>
    </template>
    <script>
    import { ref, reactive,toRefs,toRef} from "vue";
    export default {
        setup() {
            const obj = reactive({
                name: 'lwj',
                number: 0,
                add: () => {
                    //setup中 this改向了undefined
                    obj.number = ++obj.number
                },
                changename: () => {
                    obj.name = 'test'
                }
            })
            const name = toRef(obj,'name')
            const number = toRef(obj,'number')
            const add = ()=>{
                obj.number = ++obj.number
            }    
            const changename = () => {
                    obj.name = 'test'
                }
            return {name,number,add,changename}    
        }
    }
    </script>

那么这样就可以了,这样比较鸡肋,toRefs将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 [ref],在Vue2中每个响应式数据如果你打印会发现有set get属性,在vue3中就是有个ref属性了,待会演示一下,使用toRefs 与解构 可以快速解决上方的问题

    <template>
        <div>
            <button @click="add">{{ number }}</button>

            <div></div>
            {{ name }}
            <button @click="changename">修改名字</button>
        </div>
    </template>
    <script>
    import { ref, reactive,toRefs,toRef} from "vue";
    export default {
        setup() {
            const obj = reactive({
                name: 'lwj',
                number: 0,
                add: () => {
                    //setup中 this改向了undefined
                    obj.number = ++obj.number
                },
                changename: () => {
                    obj.name = 'test'
                }
            })
            var newobj = toRefs(obj)
            return {...newobj}    
        }
    }
    </script>

语法糖版

    <template>
        <div>
            <button @click="add">{{ number }}</button>
            <div></div>
            {{ obj.name }}
            <button @click="changename">修改名字</button>
        </div>
    </template>

    <script setup>
    import { ref, reactive, toRefs } from "vue";
    const obj = reactive({
            name: 'lwj',
            number: 0,
            add: () => {
                //setup中 this改向了undefined
                obj.number = ++obj.number
            },
            changename: () => {
                obj.name = 'test'
            }
    })
    const { name,number,add,changename } = toRefs(obj);
    </script>

现在我们看下ref的数据

    <template>
        
    </template>
    <script>
    import { ref, reactive,toRefs,toRef} from "vue";
    export default {
        setup() {
            const num = ref(0)   
            const obj = reactive({
                name:'lwj',
                age:18
            })

            const name = toRef(obj,'name')

            console.log(num)
            console.log(obj)
            console.log(name)
        }
    }
    </script>

那直白点,存在ifRef属性的就是可相应数据,顺带提一下,vue2中我们template标签下必须存在根标签,那vue3 无所谓了

    export default {
        setup() {
            const num = ref(0)
            const obj = reactive({
                name: 'lwj',
                age: 18
            })

            const name = toRef(obj, 'name')
            console.log(isRef(num))  // true
            console.log(isRef(obj))  // false
            console.log(isRef(name)) // true
            console.log(unref(num))  // 0 
            console.log(unref(obj))  // Object
            console.log(unref(name)) // lwj
        }
    }

isRef 判断是否是ref数据,unref如果参数是一个 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val 的语法糖函数。

computed 创建只读计算属性

接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象,或者接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象

    <template>
        <div>{{ num1 }}</div>
        <div>{{ num2 }}</div>

    </template>

    <script setup>
    import { ref, computed } from "vue";
        const num1 = ref(0)

        const num2 = computed(() => {
        return  num1.value + 1
        })
        //报错 不能修改数据  ++失败 值不变
        num2++ 
        //修改num1的值 发生改变       
        num1.value = ++ num1.value
    </script>

自定义可修改数据,相当于生成一个ref响应数据

    <template>
        <div>{{ num1 }}</div>
        <div>{{ num2 }}</div>
    </template>

    <script setup>
    import { ref, computed } from "vue";
    const num1 = ref(0)
    const num2 = computed({
        get: () => num1.value + 10,
        set: val => {
            num1.value = val - 10
        }
    })
    </script>

此时页面的值为0 10
如果执行 num2.value = 20,页面就会展示10 20,因为num1也是响应数据,当num2改变的时候执行set函数,此时num1会变为10,执行完set执行get获取值的操作,此时num2返回20,打印num2的话返回ComputedRefImpl对象,存在isRef为true的属性,现在例子比较生疏,后面结合完整点的会更清楚

watch和watchEffect都是监听器,但在写法和使用上有所区别

监听器的作用主要就是监听响应数据的改变,这玩意最好用的地方就是异步请求的时候,在监听里面完全不用担心数据未发生改变,挺喜欢这玩意

当watch监听 ref时
    <template></template>

    <script setup>
    import { ref, watch } from "vue";
    const num = ref(0)
    //监听变量  新值 老值
    watch(num, (newValue, oldValue) => {
        // 1s后打印 0 1
        console.log(`原值为${oldValue}`)
        console.log(`新值为${newValue}`)
    })
    setTimeout(() => {
        num.value++
    }, 1000)
    </script>
当watch监听reactive时
    <template></template>

    <script setup>
    import { ref, watch,reactive} from "vue";
    const num = reactive({
        count: 0
    })
    //监听变量  新值 老值
    watch(() => num.count, (newValue,oldValue) => {
        console.log(`原值为${oldValue}`)
        console.log(`新值为${newValue}`)
    })
    setTimeout(() => {
        num.count++
    }, 1000)
    </script>

watchEffect
首次加载就会监听
只能拿到最新的值
不需要指定监听的数据,组件初始化的时候就会执行一次用以收集依赖,而后收集到的依赖发生变化,这个回调才会再次执行

    <template></template>

    <script setup>
    import { reactive, watchEffect,ref } from "vue";
    const num = reactive({
        count: 0
    })
    const name = ref('lwj')

    //监听变量  新值 老值
    watchEffect(()=>{
        //首次加载打印 初始值
        console.log(num.count)
        console.log(name.value)
        //1s后打印 修改值
    })
    setTimeout(() => {
        num.count++
        name.value='test'
    }, 1000)
    </script>
先学到这里,最后演示一下vue3的变量css
    <template>
        <div>
            <h1 @click="add">{{ count }}</h1>
        </div>
    </template>

    <script setup>
    import { ref } from "vue";
    let count = ref(1)
    let color = ref('red')
    function add() {
        count.value++
        color.value = Math.random() > 0.5 ? "blue" : "red"
    }
    </script>

    <style scoped>
    h1 {
        color: v-bind(color);
    }
    </style>>
上一篇下一篇

猜你喜欢

热点阅读