新安装方式
- npm install -g @vue/cli
- vue create my-project
- npm install @vue/composition-api --save
- main.js文件中 import composition-api from ‘composition-api’
- Vue.use(composition-api)
新Api(composition-api)
setup(props , context)
- setup() 函数为API提供了统一的入口
- 执行时机:beforeCreate() 之后,Created之前
- setup() 中访问不到this,只能通过setup的第二个参数context拿到对应类似this的操作属性。context替代了this
props
- setup获取外界传入的prop,先在export default中声明props对象,接着声明传入参数的数据类型,最后调用时,通过setup的第一个参数props调用。
export default{
props:{
transData: string
}
setup(props , context){
console.log(prop.transData)
}
}
- props是响应式的,用ES6解构会消除他的响应式,可以用toRef(props)来解构
reactive({…})
- 接收一个普通的对象,返回一个响应式的数据对象
- 使用前需要先import引入
- reactive() 只能在 setup() 中使用
- 如果外界(template中)调用,setup() 会return一个响应式数据,setup() 内部调用,使用的是响应式的数据变量调用某一属性,外界调用,使用的是普通的数据变量
export default {
setup(props,context) {
let tempData = reactive({name: "jack",age:18}) //创建数据对象,里边可包含多个数据
console.log(tempData.name) //setup中,使用返回的响应式对象调用
console.log(tempData.age)
return {
...toRefs(tempData) //return响应式对象
};
}
}
<template>
<div>我的名字{{ name }}<div/> //模板中使用的还是普通的数据变量
<template/>
ref()
- 根据给定的值(基本数据类型)创建一个响应式数据对象,返回一个只包含.value属性的对象。
- ref只能用于setup() 中
- 如果外界(template中)调用,setup() 会return一个响应式数据变量,setup() 内部调用,使用的是响应式的数据变量的value值,外界调用,使用的是return的响应式数据变量,不能使用.value,也不能使用普通数据变量。
export default {
setup(props,context) {
let tempData = ref(18) //创建数据对象,里边只能是一个基本数据,如string, number
console.log(tempData.value) //setup中,使用返回的响应式数据的value属性拿到值
return {
tempData //return响应式对象
};
}
}
<template>
<div>我的年龄{{ tempData }}<div/> //模板中使用的是响应式的数据变量
<template/>
- ref在传值为null时可以作为获取虚拟DOM使用,如果 VNode 的 ref 键对应于渲染上下文中的 ref,则 VNode 的相应元素或组件实例将被分配给该 ref 的值。这是在虚拟 DOM 挂载/打补丁过程中执行的,因此模板引用只会在初始渲染之后获得赋值。
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref(null)
onMounted(() => {
// DOM元素将在初始渲染后分配给ref
console.log(root.value) // <div>这是根元素</div>
})
return {
root
}
}
}
</script>
<template>
<div ref="root">This is a root element</div>
</template>
reactive() & ref()
- 二者都用于将普通数据转为响应式数据
- 当把 ref() 创建出来的响应式数据对象,挂载到 reactive() 上时,会自动把响应式数据对象展开为原始的值,不需通过 .value 就可以直接被访问
- ref加入到reactive中,调用时使用state.ref形式,新传入的ref会覆盖掉原来的ref值,但是ref和state是相互独立的,state.ref值得改变不会影响到ref值,因此新传入的ref覆盖旧的ref,覆盖的只是指向数据的指针。
- ref用于简单的数据类型,reactive用于复杂的数据类型
- ref在return时不需要解构,state在return时需要解构
- ref在外界调用直接调用响应数据变量,reactive调用的时普通数据变量
isRef()
- 判断某个值是否是通过ref函数创建出来的
const unwrapped = isRef(foo) ? foo.value : foo
toRefs()
- 将reactive创建出来的响应式数据对象转为普通对象,只不过这个普通对象的每一个属性节点都是ref类型的响应式数据,此处用到了扩展运算符,会将state转为普通对象,因此需要用torefs将其转为响应式数据。
export default {
setup() {
const state = reactive({ count: 0 })
const increment = () => { // 定义页面上可用的事件处理函数
state.count++
}
// 这个返回对象中可以包含响应式的数据,也可以包含事件处理函数
return {
...toRefs(state),
increment
}
}
}
<template>
<div>
<p>当前的count值为:{{count}}</p>
<button @click="increment">+1</button>
</div>
</template>
computed()
- 创建计算属性,返回值是一个ref实例,因此也有.value属性
- 使用前需导入
- 创建只读的计算属性:
export default {
setup(props, context) {
const tempData = ref(0);
const computeData = computed(() => {
tempData.value += 1; //返回的computeData也是ref类型
})
console.log(tempData.value) //0
console.log(computeData.value) //1
}
}
- 创建可读可写的计算属性:
export default {
setup(props, context) {
const tempData = ref(0);
const computeData = computed({
get: () => {
tempData.value += 1;
},
set: (val) => {
tempData.value = val - 1;
}
})
console.log(tempData.value) //0
console.log(computeData.value) //1
computeData.value = 9;
console.log(tempData.value) //8
}
}
watch(arg1, arg2, arg3)
- 监视数据变化,创建时会自动调用一次,可以通过watch的第三个参数{ lazy: true }关闭。第三个参数是用来配置监听参数,例如 immediately 等
- 需要先导入
- 单一数据监听:
export default {
setup(prop, context) {
//ref类型
const tempData = ref(0)
watch(
tempData,
(newVal, oldVal) => {
console.log(newVal);
},
{
lazy: true
}
)
//reactive类型
const tempData1 =reactive({count: 0})
watch(
()=>tempData1.count,
(newVal, oldVal) => {
console.log(newVal);
},
{
lazy: true
}
)
}
}
- 多数据监听:
export default {
setup() {
//ref类型
const count = ref(0)
const name = ref('jack')
watch(
[count, name],
([newcount, newname], [oldcount, oldname]) => {
console.log(newcount, oldcount);
},
{
lazy: true
}
)
setTimeout(() => {
count.value++
name.value = 'lc'
}, 1000)
//reactive类型
const state = reactive({
count: 0,
name : 'jack'
})
watch(
[()=>state.count, ()=>state.name], //监听的数据组
([newcount, newname], [oldcount, oldname]) => { //回调函数
console.log(newVal);
},
{
lazy: true
}
)
setTimeout(() => {
state.count++
state.name = 'lc'
}, 1000)
}
}
- 清除监听
// 调用watch的返回值,执行一下就清除了。
const stop = watch(...)
stop() //清除监听
- 清除异步无效任务
这个清除函数会在如下情况下被调用:
watch 被重复执行了
watch 被强制 stop 了
export default {
setup() {
const count = ref(0)
//声明监听
const stop = watch(
count,
(newVal, oldVal, onClear) => {
const timeId = asyncPrint(newVal) //调用异步方法
onClear(() => { //重复监听会删除之前的操作
clearTimeout(timeId)
})
},
{lazy: true}
)
//异步方法
const asyncPrint = (val) => {
return setTimeout(() => {
console.log(val)
},3000)
}
}
}
- watchEffect
watchEffect在一开始的时候就会收集依赖,相比watch可控制初始化时是否立即监听,watchEffect在一开始的时候必须执行一遍,用于收集依赖,也因此watchEffect不会像watch那样会有第一个参数去指定依赖,但是在watchEffect中必须有需要监听的响应式数据才能触发监听,如果在外边改变ref1,而在watchEffect中console.log(ref2)是没效果的,但是watch是有效果的。
import { watchEffect } from 'vue'
const state1 = reactive({name: 'jack'})
setTimeout(() => {
state1.name = 'lc'
},8000)
watchEffect(() => {
console.log(state1.name) //无法监听到
})
- vue3.0中,如果watch的是一个数组对象,那么push方法不会触发监听,必须重新给数组赋值才会触发。
生命周期
- 生命周期写在setup( )中
- 需提前import引入
- 新旧生命周期对比:
beforeCreate
--- setup() // beforeCreate和created被取消,换成了setup()
created
beforeMount --- onBeforeMount(()=>{…})
mounted --- onMounted(()=>{…})
beforeUpdate --- onBeforeUpdate(()=>{…})
updated --- onUpdated(()=>{…})
beforeDestroy --- onBeforeUnmount(()=>{…})
destroyed --- onUnmounted(()=>{…})
errorCaptured --- onErrorCaptured(()=>{…})
provide
- 可以实现嵌套组件之间的数据传递, 父级组件中使用 provide() 函数向子组件传递数据
- 不限层级,只要是嵌套的子级组件
- 在setup() 中使用
- 需要先引入
- 共享普通数据
export default {
setup() {
provide('globalColor','red')
}
}
- 共享ref响应式数据
export default {
setup() {
const color = ref('red')
provide('globalColor', color)
}
}
inject
- 可以实现嵌套组件之间的数据传递, 子级组件中使用 inject() 函数接收父组件的数据
- 不限层级,只要是其父级组件,
- 在setup() 中使用
- 需要先引入
- 接收父级的传参
export default {
setup() {
inject('globalColor')
}
}
template—refs
- 通过ref() 实现对页面DOM元素和组件的引用和操作
- 父组件可以操作子组件,能拿到子组件的数据
- 实例:
export default {
setup() {
const h3ref = ref(null) //定义ref,值为null
const comChild = ref(null)
onMounted(()=>{
// h3ref.value相当于一个原生DOM
h3ref.value.style.color = 'red'
})
//能拿到子组件的DOM
const showNumber = () => {
console.log(comChild.value.count)
}
return {
h3ref,
comChild,
showNumber
}
}
}
<template>
<h3 ref='h3ref'><h3/> //绑定return的响应对象数据
<com-child ref='comChild'/>
<template/>