认识组合式 API(Composition API)
<template>
<div class="home">
{{data.count}}<hr>
<button @click="data.count++">++</button><hr>
<button @click="add()">++</button><hr>
{{data.pow}}
</div>
</template>
<script>
import { reactive,computed} from "vue";
export default {
name: 'Home',
// data(){
//
// },
// components:{
//
// },
//vue3 新增setup 但是可以与原来的共生,但命名不要冲突
setup(){
const data= reactive({
count:10,
pow:computed(()=>data.count*data.count)
})
const add=()=>{
data.count++;
}
return{
data,
add
}
}
}
</script>
setup()方法应用
<template>
<div>
<h1>这是子组件</h1>
</div>
</template>
<script>
export default {
name: "SubComp",
data(){
return{
num:1
}
},
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created');
console.log(this.num);
},
beforeMount() {
console.log('beforeMount')
},
setup(){
console.log('setup');//组件创建之前调用 setup() 没this
}
}
</script>
<style scoped>
</style>
setup()的参数
<template>
<div class="about">
<h1>父组件:关于setup()</h1>
<sub-comp @myadd="add" one="this one" :two="10" three="hello" four="world">
<h2>SLOT</h2>
</sub-comp>
</div>
</template>
<script>
import SubComp from "../components/SubComp";
export default {
name:'About',
components:{
SubComp
},
methods: {
add(str){
console.log(str);
}
}
}
</script>
<template>
<div>
<h1>这是子组件</h1>
one={{one}}<hr>
two={{two}}<hr>
<button @click="add()">++</button>
<slot>111</slot>
</div>
</template>
<script>
export default {
name: "SubComp",
props:{
one:{
type:String
},
two: {
type:Number
}
},
setup(props,{attrs, slots, emit}){
console.log(attrs.three);
console.log(slots.default());
console.log(attrs.desc);
emit('myadd', '向父组件传数据')
const add =()=>{
console.log(props.two); //10
}
return{
add
}
}
// setup(props, context) {
// context.attrs // 没有在props中声明的其他传组子组件的属性
// context.slots
// context.parent
// context.root
// context.emit
// context.refs
// }
// setup(props,context){
// console.log(context);
// console.log(context.attrs);
// console.log(context.attrs.three);
// console.log(context.slots.default());
// const add =()=>{
// console.log(this) // undefined
// console.log(props.two); //10
// props.two++;// target is readonly
// }
// return{
// add
// }
// }
// data(){
// return{
// num:1
// }
// },
// beforeCreate() {
// console.log('beforeCreate')
// },
// created() {
// console.log('created');
// console.log(this.num);
// },
// beforeMount() {
// console.log('beforeMount')
// },
// setup(){
// console.log('setup');//组件创建之前调用 setup() 没this
// }
}
</script>
<style scoped>
</style>
常用API
- ref()函数用来给定的值创建一个响应式的数据对象,ref()的返回值是一个对象,这个对象上只包含一个.value属性.
- reactive是用来创建一个响应式对象
- 将ref响应式数据挂载到reactive中,当把ref()创建出来值直接挂载到reactive()中时,会自动把响应式数据对象的展开为原始的值,不需要通过.value就可以直接访问到
- 双向绑定
- toRefs()解构响应式对象
- readonly将响应式数据变回原使数据
<template>
<div>
<h1>常用api</h1>
<div>{{num}}</div>
<button @click="num++">++</button>
<hr>
<div>{{num2}}</div>
<button @click="num2++">++</button>
<button @click="add2()">++ add2</button>
<hr>
<div>{{one}}</div>
<hr>
<div>{{two}}</div>
<hr>
<div v-for="(item,i) in two" :key="i">{{item}}</div>
</div>
</template>
<script>
import {ref,reactive,toRefs,readonly,isRef} from 'vue'
export default {
name: "SetApi",
setup(){
let num=10
let num2=ref(0)
const data=reactive({
one:100,
two:['1111','2222']
})
const add2=()=>{
console.log(num2.value)
num2.value++
data.one++
}
let num8= isRef(num2) ? num2.value :num2
let num3 =readonly(num2)
return{
num,
num2,
add2,
// data,
//...data 展开可以直接调用one和two 展开之后不再是响应式
...toRefs(data) //保持响应式
}
}
}
</script>
<style scoped>
</style>
计算属性API(computed)
- computed()用来创建计算属性,返回值是一个ref的实例
- 创建可读可写的计算属性。在使用computed函数期间,传入一个包含get和set函数的对象,可以额得到一个可读可写的计算属性
<template>
<div>
<h1>computed()</h1>
<div>num={{num}}</div>
<hr>
<button @click="num++">{{num}}++</button>
{{all}}
<hr>
<input type="text" v-model="user.first">
<input type="text" v-model="user.end">
</div>
</template>
<script>
import {ref,reactive,computed} from "vue";
export default {
name: "Comp",
setup(){
let num= ref(0)
const user = reactive({
first:'php',
end:'cn'
})
const all = computed(() =>{
return user.first + '.' +user.end
})
return{
num,
user,
all
}
}
}
</script>
<style scoped>
</style>
侦听器watch
监听数字变化
<template>
<div>
<h1>Watch</h1>
<h2>a={{a}}, b={{b}}</h2>
<button @click="a++">a++</button>
<button @click="b++">b++</button>
</div>
</template>
<script>
import {ref,reactive,watch,watchEffect,toRef} from 'vue';
export default {
name: "Watch",
setup(){
let a= ref(0)
let b=ref(2)
// watchEffect 它与 watch 的区别主要有以下几点:
//懒执行副作用;
//更明确哪些状态的改变会触发侦听器重新运行副作用;
//访问侦听状态变化前后的值。
// watch(a,(newa,olda)=>{
// console.log('a的值:'+a.value+'############# a的新值:'+ newa+',a的原值:'+olda)
// },{immediate:true})
// {immediate:true} 默认执行一次
watch([a,b],([newa,newb],[olda,oldb])=>{
console.log('a的值:'+a.value+'############# a的新值:'+ newa+',a的原值:'+olda)
console.log('b的值:'+b.value+'############# b的新值:'+ newb+',b的原值:'+oldb)
},{immediate:true})
// watch(()=>{
// console.log(a.value+'++++++++++++++'+b.value)
// })
// watchEffect(()=>{
// console.log(a.value+'++++++++++++++'+b.value)
// })
return{
a,
b
}
}
}
</script>
<style scoped>
</style>
监听对象
<template>
<div>
<h1>Watch</h1>
<h2>a={{a}}, b={{b}}</h2>
<button @click="a++">a++</button>
<button @click="b++">b++</button>
<hr>
<input type="text" v-model="nnn"><hr>
<input type="text" v-model="age"><hr>
{{nnn}} --- {{age}}
</div>
</template>
<script>
import {ref,reactive,watch,watchEffect,toRefs} from 'vue';
export default {
name: "Watch",
setup(){
let a= ref(0)
let b=ref(2)
const user = reactive({
age:30,
nnn:'xiaoming'
})
watch([()=>user.age,()=>user.nnn],()=>{
console.log(user.age+'***************')
},{immediate:true})
return{
a,
b,
...toRefs(user)
}
}
}
</script>
<style scoped>
</style>
生命周期
选项式 API 的生命周期选项和组合式 API 之间的映射
beforeCreate -> 使用 setup()
created -> 使用 setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeUnmount -> onBeforeUnmount
unmounted -> onUnmounted
errorCaptured -> onErrorCaptured
renderTracked -> onRenderTracked
renderTriggered -> onRenderTriggered
activated -> onActivated
deactivated -> onDeactivated
<template>
<div>
</div>
</template>
<script>
import {onMounted, onUpdated} from 'vue';
export default {
name: "Time",
beforeCreate() {
console.log('beforeCreate() ---');
},
created() {
console.log('create() .....');
},
mounted() {
console.log('mounted() .....')
},
setup() {
console.log('setup().....');
let one = '11111';
onMounted(()=>{
console.log(one+'onmounted.....')
});
onUpdated(()=>{
console.log('onUpdate....');
})
}
}
</script>
<style scoped>
</style>
在组合API中provide和inject使用
父子组件:通过props,$emit,【$root,$parent,$children】
非父子组件:Vuex实现,父子层层传递、$ref
provide/inject 这对选项允许一个祖先组件向其所有子孙后代组件注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
provide就相当于加强版父组件prop,可以跨越中间组件,inject就相当于加强版子组件的props
使用办法
provide 提供变量:Object | () => Object
inject 注入变量: Array<string> | { [key: string]: string | Object }
祖
<template>
<div>
<h1>父组件</h1>
<two></two>
</div>
</template>
<script>
import Two from "../components/Two";
import {reactive,provide,ref} from "vue";
export default {
name: "One",
components:{
Two
},
//原来的方法
// provide(){
// return{
// count:99
// }
// },
setup() {
const name = ref('lmonkey')
const obj = reactive({
name: 'lmonkey',
age: '3'
})
provide('name', name)
provide('animal', obj)
}
}
</script>
<style scoped>
</style>
孙
<template>
<div>
<h1>孙组件</h1>
<!-- {{count}}---<hr>-->
{{name}}--<hr>
{{animal}}---<hr>
<div v-for="(item,i) in animal" :key="i">{{i}}--{{item}}</div>
<hr>
<input type="text" v-model="name"><hr>
</div>
</template>
<script>
import {inject} from "vue";
export default {
name: "Sun",
// inject:['count'],
setup() {
// 用法: inject(key)
const name = inject('name')
const animal = inject('animal')
return {
name,
animal
}
}
}
</script>
<style scoped>
</style>
Composition API结合路由
<template>
<div>
<h1>Router</h1>
</div>
</template>
<script>
import {useRoute,useRouter} from 'vue-router';
export default {
name: "Router",
setup(){
const route=useRoute();
const router=useRouter();
console.log(route);
console.log(route.fullPath);
console.log(route.query);
console.log(route.params.uid) //user/14
console.log(router);
// setTimeout(()=>{
// router.push({path:'/',query:{name:1111,age:2222}})
// },5000)
}
}
</script>
<style scoped>
</style>
import { createStore } from 'vuex'
export default createStore({
state: {
num1:11,
num2:22
},
getters:{
double1(state) {
return state.num1 * 2;
},
double2(state) {
return state.num2 * 2;
}
},
mutations: {
changenum1(state, payload){
state.num1 = payload;
},
changenum2(state, payload){
state.num2 = payload;
}
},
actions: {
timecnum1({commit, state}) {
setTimeout(()=>{
commit('changenum1', 44);
}, 5000)
},
timecnum2({commit, state}) {
setTimeout(()=>{
commit('changenum2', 55);
}, 5000)
}
},
modules: {
}
})
<template>
<h2>Vuex Api useStore</h2>
<h3>num1: {{$store.state.num1}}</h3>
<h3>getter-num1: {{$store.getters.double1}}</h3>
<button @click="cnum1(33)">修改num1:{{$store.state.num1}}</button>
<button @click="canum1">修改anum1:{{$store.state.num1}}</button>
<hr>
<h3>num2: {{num2}}</h3>
<h3>getters-num2: {{double2}}</h3>
<button @click="cnum2(33)">修改num2:{{num2}}</button>
<button @click="canum2">修改anum2:{{num2}}</button>
</template>
<script>
import {useStore} from 'vuex';
import {computed} from 'vue';
export default {
name: "VuexApi",
setup() {
const store = useStore();
return {
num2:computed(()=>store.state.num2),
double2:computed(()=>store.getters.double2),
cnum2:(newnum)=>{
store.commit('changenum2', newnum);
},
canum2:()=>{
store.dispatch('timecnum2');
}
}
},
methods: {
cnum1(newnum) {
this.$store.commit('changenum1', newnum);
},
canum1() {
this.$store.dispatch('timecnum1');
}
}
}
</script>
<style scoped>
</style>