美文网首页
vue3.x全家桶+vite(二)composition api

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

作者: 感觉不错哦 | 来源:发表于2021-12-15 17:01 被阅读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>>
    

    相关文章

      网友评论

          本文标题:vue3.x全家桶+vite(二)composition api

          本文链接:https://www.haomeiwen.com/subject/pvbjfrtx.html