组合式API(Compositon API)

1.setup方法

setup() 函数是vue3中专门新增的方法,可以理解为 Composition Api 的入口

# src/Views/Home.vue
# 1、创建setup方法
# 1.1、创建一个常量
# 1.2、必须 return 返回,才能给模版使用
<template>
    <div>
        <div>{{ data }}</div>
    </div>
</template>
<script>
export default {
    name: "Home",
    setup() {
        const data = 10;
        return {
            data
        }
    }
};
</script>


# 2、点击方法,不能使用
<template>
    <div>
        <div>{{ data }}</div>
        <button @click="data++">加++</button>
    </div>
</template>
<script>
export default {
    name: "Home",
    setup() {
        const data = 10;
        return {
            data
        }
    }
};
</script>

  
# 3、reactive 返回对象的响应式副本
# 所有的 api 都是方法、函数
<template>
    <div>
        <div>{{ data.number }}</div>
        # 3.2、使用 reactive 方法创建的数据,就能相应了
        <button @click="data.number++">加++</button>
        # 3.3、执行方法
        <button @click="jian()">减++</button>
    </div>
</template>
<script>
# 3.1、引入 reactive 方法
import {reactive} from 'vue';
export default {
    name: "Home",
    setup() {
        # 3.2、使用reactive方法,创建数据
        const data = reactive({
            number : 10
        })
        # 3.4、创建方法
        const jian = () => {
            data.number--;
        }
        # 3.5、方法也要return
        return {
            data,
            jian
        }
    }
};
</script>


# 4、计算属性
<template>
    <div>
        <div>{{ data.number }}</div>
        # 4.3、使用数据
        <div>{{ data.jisuan }}</div>
        <button @click="data.number++">加++</button>
        <button @click="jian()">减++</button>
    </div>
</template>
<script>
# 4.1、引入 computed 方法
import {reactive,computed} from 'vue';
export default {
    name: "Home",
    setup() {
        # 4.2、computed 计算属性
        const data = reactive({
            number : 10,
            jisuan : computed( ()=>data.count * data.count )
        })
        const jian = () => {
            data.number--;
        }
        return {
            data,
            jian
        }
    }
};
</script>
  

# 5、组合使用
<template>
    <div>
        <div>{{ name }}</div>
        <div>{{ data.number }}</div>
        <div>{{ data.jisuan }}</div>
        <button @click="data.number++">加++</button>
        <button @click="jian()">减++</button>
    </div>
</template>
<script>
import {reactive,computed} from 'vue';
export default {
    name: "Home",
    # 5.1、可以和之前学的参数 共生
    data() {
        return {
            name: "php中文网"
        }
    },
    # 5.2、components 导入组件,还是得用原来的
    components:{
            
    },
    setup() {
        const data = reactive({
            number : 10,
            # 5.3、使用 this 报错
            jisuan : computed( ()=>this.count * this.count )
            jisuan : computed( ()=>data.count * data.count )
        })
        const jian = () => {
            data.number--;
        }
        return {
            data,
            jian
        }
    }
};
</script>

# 6、setup 方法里没 this,因为它是最先运行的
<template>
    <div>
        <div>{{ name }}</div>
    </div>
</template>
<script>
export default {
    name: "Home",
    data() {
        return {
            name: "php中文网"
        }
    },
    # 6.1、打印结果是 setup 先运行
    beforeCreate() {
        console.log("beforeCreate");
        # 6.2、这个打印this.name,空值,但不报错,说明有this
        console.log(this.name);
    },
    created() {
        console.log("created");
        # 6.3、这个打印this.name,就有值,说明已经运行了data
        console.log(this.name);
    },
    beforeMount() {
        console.log("beforeMount");
    },
    setup() {
        console.log("setup");
        # 6.4、这个打印this.name,就会报错,说明没有this,就是这样设计的
        console.log(this.name);
    }
};
</script>


# 7、Home.vue 文件引入 One.vue组件
<template>
    <div>
        # 7.1、使用one组件,传2个值
        <one one="1111" two="2222"></one>
        # 7.7、使用one组件,传4个值,前2个值会被props接收,后2个值不会被props接收
        <one one="1111" two="2222" three="3333" four="4444"></one>
        # 7.8、插槽
        <one one="1111" two="2222" three="3333" four="4444">
            <div>这是插槽</div>
        </one>
    </div>
</template>
<script>
import One from "../components/One";
export default {
    components: {
        One
    }
};
</script>
# 7.2、创建个组件 src/components/One.vue
<template>
    <div>
        one = {{ one }} 

        two = {{ two }} 

        # 7.9、插槽位置
        <slot>插槽</slot>
    </div>
</template>
<script>
    export default {
        name: "One",
        # 7.3、接收2个传值
        props: {
            one: {
                type: String,
            },
            two: {
                type: String,
            }
        },
        # 7.4、在setup里不能使用this,就无法使用props的数据
        # 7.5、setup方法,第一个参数:就是props里接收的数据,参数名可以更改
        # 7.6、第二个参数:没有被props接收的数据,未声明的数据。比如7.7多传2个参数
        setup(props,context) { // setup(props,{attrs,slots}) 也可以结构赋值 展开
            console.log(props);
            console.log(context); // 里面有attrs参数,就是未接收的数据
            console.log(context.attrs); // Attribute (非响应式对象,等同于 $attrs)
            console.log(context.slots); // 插槽 (非响应式对象,等同于 $slots)
            console.log(context.emait); // 触发事件 (方法,等同于 $emit)
            console.log(context.expose); // 暴露公共 property (函数)
            
            # 7.10、打印插槽数据
            console.log(context.slots.default());
        }
    };
</script>

2.常用API

# 1、setup里不能使用this,数据也不能改变(非响应式)
<template>
    <div>
        <div>{{ num }}</div>
        <button @click="num++">加++</button>
    </div>
</template>
<script>
export default {
    setup() {
        let num = 10
        return {
            num
        }
    }
};
</script>

 
# 2、ref 接受一个内部值并返回一个响应式且可变的 ref 对象
<template>
    <div>
        <div>{{ num }}</div>
        <button @click="num++">加++</button>
        <button @click="add()">js加++</button>
    </div>
</template>
<script>
import {ref} from 'vue';
export default {
    setup() {
        # 2.1、使用ref方法处理后,就变为响应式了
        let num = ref(10)
        # 2.2、用方法处理,没效果
        const add = () => {
            num++
            # 2.3、打印后,发现里面有个value
            console.log(num)
            # 2.4、所以要使用 .value
            num.value++
        }
        return {
            num,
            add
        }
    }
};
</script>
  

# 3、reactive 函数接收一个普通对象,返回一个响应式的数据对象
<template>
    <div>
        <div>{{ data1.num }}</div>
        <button @click="add1()">加++</button>
        <div>{{ data2.num }}</div>
        <button @click="add2()">加++</button>
    </div>
</template>
<script>
import { ref, reactive } from "vue";
export default {
    setup() {
        # 3.1、ref 创建数据
        let data1 = ref({
            num: 10
        })
        const add1 = () => {
            console.log(data1)
            data1.value.num++
        }
        # 3.2、reactive 创建数据
        let data2 = reactive({
            num: 10
        })
        const add2 = () => {
            # 3.2.1、打印后,就会少一层.value
            console.log(data2)
            data2.num++
        }
        # 3.3、返回值在模版中,会多一层 {{data1.num}},之前是 {{num}}
        return {
            data1,
            data2,
            add1,
            add2
        }
    }
};
</script>
  

# 4、使用结构赋值,就可以减少一层,但是会导致 数据不能相应
<template>
    <div>
        <div>{{ data2.num }}</div>
        <div>{{ num }}</div>
        # 4.1、点击后,{{num}}不变,不是响应式的了
        <button @click="add2()">加++</button>
    </div>
</template>
<script>
# 4.2、引入 toRefs 方法:返回时转换为ref,在不丢失响应性的情况下对返回的对象进行解构/展开
import { reactive,toRefs } from "vue";
export default {
    setup() {
        let data2 = reactive({
            num: 10,
            name : "欧阳克"
        })
        const add2 = () => {
            data2.num++
        }
        return {
            data2,
            add2,
            ...data2,
            ...toRefs(data2) // toRefs 返回时转换为ref
        }
    }
};
</script>


# 5、readonly 接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理
# 5.1、isRef 检查值是否为一个 ref 对象
<template>
    <div>
        <div>{{ read.num }}</div>
        <button @click="add()">加++</button>
    </div>
</template>
<script>
import { reactive, ref, readonly, isRef } from "vue";
export default {
    setup() {
        let data = reactive({
            num: 10,
            name: "欧阳克",
        });
        # 5.2、readonly 方法把data数据,设置为只读
        const read = readonly(data);
        read.num++; // 会报错

        const add = () => {
            read.num++; // 会报错
        };
        # 5.3、如果是ref创建的数据,isRef就会返回true
        let data1 = ref(10);
        console.log(isRef(data1));
        return {
            read,
            add,
        };
    }
};
</script>

3.侦听API

# 1、watch 侦听数据的改变
<template>
    <div>
        <div>a = {{ a }} b = {{ b }}</div>
        <button @click="a++">a++</button>
        <button @click="b++">b++</button>
    </div>
</template>
<script>
import { reactive, ref, watch } from "vue";
export default {
    setup() {
        let a = ref(0)
        let b = ref(0)

        # 1.1、默认情况下,它有惰性的,只有当被侦听的源发生变化时才执行回调
        watch(() => {
            console.log(a)
            console.log(a.value)
            console.log(b.value)
        })
        # 1.2、侦听单个数据源
        watch(a, () => {
            console.log(a);
            console.log(a.value);
        });
        # 1.3、新老值
        watch(a, (new_a, old_a) => {
            console.log("新:" + new_a);
            console.log("老:" + old_a);
        });

        # 1.4、侦听多个数据源
        watch([a,b], () => {
            console.log(a.value);
            console.log(b.value);
        });
        # 1.5、新老值
        watch([a,b], ([new_a,new_b],[old_a,old_b]) => {
            console.log('a新值:'+new_a+',a老值:'+old_a);
            console.log('b新值:'+new_b+',b老值:'+old_b);
        });
        return {
            a,
            b
        }
    }
};
</script>
  

# 2、侦听对象
<template>
    <div>
        <input type="text" v-model="name"/><br>
        <input type="text" v-model="age"/><br>
    </div>
</template>
<script>
import { reactive, ref, watch, toRefs } from "vue";
export default {
    setup() {
        const obj = reactive({
            name : "欧阳克",
            age : 38
        })
        # 2.1、对象数据改变,会被侦听。侦听对象里的全部数据
        watch(obj, () => {
            console.log(obj.name);
            console.log(obj.age);
        })
            
        # 2.2、侦听对象里的单个数据
        # 2.2.1、之间写对象里的数据,会报错
        watch(obj.age, () => {
            console.log(obj.age);
        })
        # 2.2.2、参数写成方法
        watch(()=>obj.age, () => {
            console.log(obj.age);
        })
        # 2.2.3、多个参数
        watch([()=>obj.age,()=>obj.name], () => {
            console.log(obj.age);
            console.log(obj.name);
        })

        return {
            ...toRefs(obj)
        }
    }
};
</script>


# 3、watchEffect 侦听数据的改变,默认会执行一次
<template>
    <div>
        <div>a = {{ a }} b = {{ b }}</div>
        <button @click="a++">a++</button>
        <button @click="b++">b++</button>
    </div>
</template>
<script>
import { reactive, ref, watch, watchEffect } from "vue";
export default {
    setup() {
        let a = ref(1)
        let b = ref(2)
        watchEffect(() => {
            console.log(a)
            console.log(a.value)
            console.log(b.value)
        })
        return {
            a,
            b
        }
    }
};
</script>

4.在组合API中provide和inject使用

# 1、src/Views/Home.vue 文件
<template>
    <div>
        <div>{{ name }}</div>
        <one></one>
    </div>
</template>
<script>
import { ref } from "vue";
import One from "../components/One";
export default {
    components: {
        One
    },
    data() {
        return {
            name: ref("欧阳克")
        }
    },
    provide() {
        return {
            name: "欧阳克",
            name: this.name // 还可以用data里的变量
        }
    }
};
</script>


# 1.1、创建儿子文件:src/components/One.vue文件
<template>
    <div>
        <div>这是one</div>
        <two></two>
    </div>
</template>
<script>
import Two from "../components/Two";
export default {
    name: "One",
    components: {
        Two
    }
};
</script>
  
# 1.2、创建孙子文件:src/components/Two.vue文件
# 1.2.1、使用 inject 参数,获取它爷爷的数据
<template>
    <div>
        <div>这是two {{ name }}</div>
    </div>
</template>
<script>
export default {
    name: "Two",
    inject: ["name"]
};
</script>

----------------------------------------
  
# 2、在组合API中provide和inject使用
# 2.1、src/Views/Home.vue 文件
<template>
    <div>
        <div>{{ name }}</div>
        <one></one>
    </div>
</template>
<script>
import { ref, provide } from "vue";
import One from "../components/One";
export default {
    components: {
        One
    },
    setup() {
        let name = ref("欧阳克");
        provide("name", name)
    }
};
</script>
# 2.2、src/components/Two.vue文件
<template>
  <div>
    <div>这是two {{ name }}</div>
  </div>
</template>
<script>
import { inject } from "vue";
export default {
    name: "Two",
    setup() {
        let name = inject("name");
        return {
            name
        }
    },
};
</script>

5.路由

# 1、获取路由:useRoute, useRouter (要在 setup 函数中访问路由,请调用 useRouter 或 useRoute 函数)
<template>
    <div>
        <div>欧阳克</div>
    </div>
</template>
<script>
import { useRoute, useRouter } from "vue-router";
export default {
    setup() {
        const route = useRoute();
        const router = useRouter();

        console.log(route);
        console.log(route.fullPath);
        console.log(route.query);
        console.log(route.params);
        console.log(router);
        
        router.push({
            path : "/new",
            query: { id:10 }
        });
    }
};
</script>


# 2、获取vuex状态管理器:useStore
<template>
    <div>
        <div>欧阳克</div>
    </div>
</template>
<script>
import { useStore } from "vuex";
export default {
    setup() {
        const store = useStore();
        console.log(store);
        console.log(store.state.num);
    }
};
</script>
# 2.1、/src/store/index.js 文件
import { createStore } from "vuex";
const state = {
    num: 10,
};
export default createStore({
    state
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三年之约-第一年

你的鼓励是对我最大的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值