前言
vue3.0 Rc
(候选公布版本)曾经于 7 月 18
上线,离正式版本公布曾经不远了,鉴于此,自己就通过 @vue/composition-api
这个 Vue Composition API
来当时体验下 3.0 的新个性,为当前能疾速上手新版本做筹备。
筹备工作
下载与引入
- 下载体验版 api
npm i @vue/composition-api
- 引入与应用
1. 在 main.js 中要引入全副的 api
import VueCompositionApi from '@vue/composition-api'
Vue.use(VueCompositionApi)
2. 在页面中按需引入 api
import {须要应用的 api} from '@vue/composition-api'
tips:
main.js
和部分页面都须要引入,不能只在页面中引入。
开发与应用
reactive 和 toRefs
reactive
创立响应式数据,toRefs
把一般数据转换成响应式数据
<template>
<div class="home">
<span>{{name}}</span>
<span>{{num}}</span>
<button @click="btn"> 按钮 </button>
<button @click="btn2"> 按钮 2 </button>
</div>
</template>
<script>
// reactive 创立响应式数据对象 -- 相似 data
import {reactive, toRefs} from '@vue/composition-api'
export default {
name: 'Home',
setup () {
// state 对象
const state = reactive({name: 'hello world'})
// modelData
const modelData = reactive({num: 1})
const btn = () => modelData.num++
const btn2 = () => {
state.name = '我是不双向绑定的数据, 没有 toRefs 转换不可更改'
return state
}
return {
...state,
...toRefs(modelData), // 把数据转换为响应式
btn, // 事件
btn2
}
}
}
</script>
tips:
- 在
setup
中是没有this
的- 数据、办法都写在
setup
外面。- 办法里扭转值需
return
这个值- 用了
...
运算符后应用reactive
创立进去的数据都不是响应式数据了, 须要应用toRefs
转换为ref()
类型的响应式数据
ref(举荐)
- 和
reactive
一样创立响应式数据,但更举荐应用。
<template>
<div class="RefCom">
<span>{{refCount}}</span>
<button @click="refCount+=1">+1</button>
</div>
</template>
<script>
import {ref, reactive} from '@vue/composition-api'
export default {
name: 'RefCom',
setup (props, { root}) {const refCount = ref(0) // 创立响应式数据
console.log(refCount.value)
const data = reactive({refCount})
console.log(data.refCount)
data.refCount++
console.log(data.refCount)
return {
...data,
refCount
}
}
}
</script>
- 模板上的 ref– 获取 dom
// 父组件
<template>
<div class="Father">
<h1 ref="h1Ref"> 父组件 </h1>
<som ref="somRef"></som>
</div>
</template>
<script>
import som from './Som'
import {ref, onMounted} from '@vue/composition-api'
export default {
name: 'Father',
components: {som},
setup (props, { root}) {const h1Ref = ref(null) // 赋值 null
const somRef = ref(null)
onMounted(() => {console.log(h1Ref.value, 'h1 的 dom')
console.log(somRef.value, 'som 的 dom')
})
return {
h1Ref, // 要和模板上 ref 值雷同
somRef
}
}
}
</script>
// 子组件
<template>
<div class="Som">
<h3> 子组件 </h3>
</div>
</template>
<script>
export default {
name: 'som',
setup (props, { root}) {}}
</script>
tips:
ref
括号里的值就是refCount
的值,括号里的值能够是各种类型的值。- 在
setup
要通过 xxx.value 获取ref
转换的值。- 模板中无需通过 xxx.value 展现数据,间接 {{xxx}} 即可,在
return
时曾经进行了转换了。ref
包裹创立进去的值是个对象, 外面就一个属性value
。- 用
reactive
包裹ref
创立的值不须要通过 XXX.value 拜访- 新的
ref
会笼罩旧的ref
的值- 通过
isRef
能够判断是否是ref
创立进去的。
computed
计算属性: 可创立可读可写的计算属性。
<template>
<div class="RefCom">
<span> 原值:{{refCount}}</span> |
<span>
计算属性值:{{onlyReadComputed}}
</span> |
<button @click="refCount+=1">+1</button>
</div>
</template>
<script>
import {ref, computed} from '@vue/composition-api'
export default {
name: 'RefCom',
setup (props, { root}) {const refCount = ref(0)
// 只读的计算属性
const onlyReadComputed = computed(() => refCount.value + 1)
// 可读可写的计算属性
const rwComputed = computed({get: () => refCount.value + 1,
set: value => {refCount.value = value - 1}
})
console.log(onlyReadComputed, '只读计算属性的值')
rwComputed.value = 11
console.log(rwComputed, '可读可写计算属性的值')
return {
refCount,
rwComputed,
onlyReadComputed
}
}
}
</script>
watch
监听数据的变动
<template>
<div class="RefCom">
<span>{{refCount}}</span>
<span>{{name}}</span>
<button @click="stopWatch"> 进行 watch</button>
<input v-model="inputValue" />
</div>
</template>
<script>
import {ref, reactive, watch, toRefs} from '@vue/composition-api'
export default {
name: 'watch',
setup (props, { root}) {const refCount = ref(0)
const inputValue = ref('')
const state = reactive({name: '张总'})
/* --- 监听单个 --- */
// ref
const stop = watch(
refCount,
(newValue, oldValue) => {console.log(refCount.value)
console.log('新值:' + newValue, '旧的值:' + oldValue)
}
)
const stopWatch = () => {stop()
}
// reactive
watch(() => state.name,
(newValue, oldValue) => {// console.log(refCount.value)
console.log('新值:' + newValue, '旧的值:' + oldValue)
}
)
/* --- 监听多个 --- */
watch([() => refCount, () => state.name],
([newRefCount, newName], [oldRefCount, oldName]) => {console.log('newRefCount:' + newRefCount.value, 'newName:' + newName)
console.log('oldRefCount:' + oldRefCount.value, 'oldName:' + oldName)
}
)
setTimeout(() => {refCount.value++}, 1000)
setTimeout(() => {state.name = '李总'}, 3000)
// 异步打印
const asyncPrint = (val) => {return setTimeout(() => {console.log(val)
}, 1000)
}
// ref
watch(
inputValue,
(newValue, oldValue, clean) => {const timeId = asyncPrint(newValue)
// 每当数据变动的时候革除定时器
clean(() => clearTimeout(timeId))
}
)
return {...toRefs(state),
refCount,
stopWatch,
inputValue
}
}
}
</script>
tips:
ref
和reactive
的值的监听办法不同,reactive
需用办法返回值,() => xxx,ref
可间接应用。- 当监听多个时,不论是
ref
还是reactive
创立的值,都须要用办法返回- 在监听多个值时,用数组来解构新旧值时,新值和旧值别离在不同的数组里,和
vue2.x
不一样。watch
监听返回新值、旧值时还返回了个函数,以后函数在watch 被反复执行
和stop
操作时产生,可做些革除操作。常见利用场景有防抖。- 防抖:就是对于频繁触发的事件增加一个延时同时设定一个最小触发距离,如果触发距离小于设定的距离,则革除原来的定时,从新设定新的定时;如果触发距离大于设定距离,则保留原来的定时,并设置新的定时;防抖的后果就是频繁的触发转变为触发一次
生命周期
- beforeCreate -> setup()
- created -> setup
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeDestroy -> onBeforeUnmount
- destroyed -> onUnmounted
- errorCaptured -> onErrorCaptured
<template>
<div class="Father">
</div>
</template>
<script>
import {onMounted, onUpdated, onBeforeUnmount} from '@vue/composition-api'
export default {
name: 'Father',
setup (props, { root}) {onMounted(() => {console.log('onMounted')
})
onUpdated(() => {console.log('onUpdated')
})
onBeforeUnmount(() => {console.log('onBeforeUnmount')
})
}
}
</script>
tips:
- 去除了
beforeCreate
和created
生命周期,间接就在setup
中,setup
执行程序 是beforeCreate
后,created
前- 其余生命周期就在本来前加上
on
,性能没有什么变动,且定义在setup
函数中- 举荐申请都放在
onMounted
中
依赖注入
- provide
// 父组件
<template>
<div class="Father">
<h1> 父组件 </h1>
<button @click="color='red'"> 红色 </button>
<button @click="color='blue'"> 蓝色 </button>
<button @click="color='yellow'"> 黄色 </button>
<som></som>
</div>
</template>
<script>
import som from './Som'
import {provide, ref} from '@vue/composition-api'
export default {
name: 'Father',
components: {som},
setup (props, { root}) {const color = ref('red') // 响应式的值, 父组件批改可影响子孙后代
// 注入值
provide('color', color)
return {color}
}
}
</script>
// 子组件
<template>
<div class="Som">
<h3> 子组件 </h3>
<Grandson />
</div>
</template>
<script>
import Grandson from './Grandson'
export default {
name: 'som',
components: {Grandson},
setup (props, { root}) {}}
</script>
- inject
// 孙子组件
<template>
<div class="Grandson">
<h5 :style="{color:color}"> 孙子组件 </h5>
</div>
</template>
<script>
import {inject} from '@vue/composition-api'
export default {
name: 'Grandson',
setup (props, { root}) {
// 接管值
const color = inject('color')
return {color}
}
}
</script>
路由跳转
<template>
<div class="home">
<button @click="jump"> 跳转 </button>
</div>
</template>
<script>
export default {
name: 'Home',
setup (props, { root}) {const jump = () => root.$router.push('/about')
return {jump}
}
}
</script>
tips:
root
指代的就是vue
对象, 即this
,且名字是不可更改的。
props
// 父
<template>
<div class="about">
<h1>This is an about page</h1>
<div>{{num}}</div>
<button @click="btn"> 减少 </button>
<HelloWorld msg="我是 props 传进去的值" />
</div>
</template>
// 子
<template>
<div class="hello">
<h1>{{msg}}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {msg: String},
setup (props) {console.log(props)
}
}
</script>