创建项目之前的准备
在创建项目之前需要确认是否安装了vue脚手架
安装脚手架
npm install -g @vue/cli
上面安装的是Vue CLI3版本
创建项目
vue create 项目名称
创建步骤
node版本在10.0以上
值得注意的Vue3 新特性
Composition API(组合 API)
composition-api解决了什么问题
使用传统的option配置方法写组件的时候问题,随着业务复杂度越来越高,代码量会不断的加大;由于相关业务的代码需要遵循option的配置写到特定的区域,导致后续维护非常的复杂,同时代码可复用性不高,而composition-api就是为了解决这个问题而生的。
Composition API在使用时需要先引入
import { reactive, toRefs, computed } from "vue";
1.setup是composition-api的入口函数
2.在声明周期beforeCreate事件之前被调用;
3.可以返回一个对象,这个对象的属性被合并到渲染上下文,并可以在模板中直接使用;
接收props对象作为第一个参数,接收来的props对象,可以通过watchEffect监视其变化。
接受context对象作为第二个参数,这个对象包含attrs,slots,emit三个属性。
4.context替代了this
由于setup被执行的时候,组件示例还没有创建完成,因此在setup里面没有this。这意味着除了props,你无法使用组件内定义的其他任何属性,包括本地状态、计算属性和方法等。
setup(props, ctx) {
ctx.emit('传参')
}
当然,还能把emit直接解构出来使用更方便:
setup(props, { emit }) {
emit('ooxx')
}
语法糖介绍
compositon-api提供了一下几个函数
- ref
- reactive
- toRefs
- computed
- watch
- watchEffect
- 生命周期的hooks
ref
接受一个参数值并返回一个响应式且可改变的ref对象
- ref对象拥有一个指向内部值的单一属性 .value
- 当ref在模板中使用的时候,他会自动解套,无需在模板内额外书写 .value
import { reactive, toRefs, computed } from "vue";
export default {
const count = ref(0)
const countAdd = ()=>{
count.value ++
}
return {
count
countAdd
}
}
reactive
接收一个普通对象然后返回该普通队形的响应式代理,等同于2.x的Vue.observable() 1. 响应式转换是“深层的”:会影响对象内部所有嵌套的属性
import { reactive, toRefs, computed } from "vue";
export default {
const state = reactive({ count: 0,
double: computed(()=>state.count * 2)
})
return {
... toRefs(state)
double
}
}
import { reactive, toRefs, computed } from "vue";
export default {
const state = reactive({ count: 0,
double: computed(()=>state.count * 2)
})
return toRefs(state)
}
reactive
和ref
之间做选择
二者都用于将普通数据转为响应式数据
1.当把 ref() 创建出来的响应式数据对象,挂载到 reactive() 上时,会自动把响应式数据对象展开为原始的值,不需通过 .value 就可以直接被访问
2.ref加入到reactive中,调用时使用state.ref形式,新传入的ref会覆盖掉原来的ref值,但是ref和state是 相互独立的,state.ref值得改变不会影响到ref值,因此新传入的ref覆盖旧的ref,覆盖的只是指向数据的指针。
3.ref用于简单的数据类型,reactive用于复杂的数据类型
4.ref在return时不需要解构,state在return时需要解构
5.ref在外界调用直接调用响应数据变量,reactive调用的时普通数据变
6.关联性比较强的数据选择reactive,代码显得比较完整和整洁
toRefs
1.toRefs API提供了一个方法可以把reactive的值处理为ref
2.将reactive创建出来的响应式数据对象转为普通对象,只不过这个普通对象的每一个属性节点都是ref类型的响应式数据,此处用到了扩展运算符,会将state转为普通对象,因此需要用toRefs将其转为响应式数据。
import { reactive, toRefs, computed } from "vue";
export default {
setup() {
const state = reactive({ count: 0 })
const increment = () => { // 定义页面上可用的事件处理函数
state.count++
}
// 这个返回对象中可以包含响应式的数据,也可以包含事件处理函数
return {
...toRefs(state),
increment
}
}
}
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方法不会触发监听,必须重新给数组赋值才会触发。
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元素和组件的引用和操作
- 父组件可以操作子组件,能拿到子组件的数据
- 实例
<template>
<h3 ref='h3ref'><h3/> //绑定return的响应对象数据
<com-child ref='comChild'/>
<template/>
<script>
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
}
}
}
</script>
生命周期
生命周期写在setup()中
需提前import引入
import { onBeforeMount, onMounted, reactive, watchEffect } from 'vue'
新旧生命周期对比:
beforeCreate --- setup()
created --- setup()
beforeMount --- onBeforeMount(()=>{…})
mounted --- onMounted(()=>{…})
beforeUpdate --- onBeforeUpdate(()=>{…})
updated --- onUpdated(()=>{…})
beforeDestroy --- onBeforeUnmount(()=>{…})
destroyed --- onUnmounted(()=>{…})
errorCaptured --- onErrorCaptured(()=>{…})