Vue3.0新特性
初始化项目
-
安装 vue-cli3 (脚手架)
在 cmd 窗口(注意了 这里得先下载node跟npm哦)npm install -g @vue/cli # OR yarn global add @vue/cli
-
创建项目
vue create my-project # OR vue ui
注意: 这里可能会有报错,大家可以尝试一下用管理者模式打开 powershell ,说不定能解决
-
在项目中安装 composition-api 体现vue3 新特性
npm install @vue/composition-api --save # OR yarn add @vue/composition-api
-
在使用任何 @vue/composition-api 提供的能力前,必须先通过 Vue.use() 进行安装
import Vue from 'vue' import App from './App.vue' import VueCompositionAPI from '@vue/composition-api' Vue.use(VueCompositionAPI)
去除console控制台等的报错
首先我们在创建脚手架的时候,可以选择不添加使用eslint 校验代码
不过嘛= =有些时候手贱也是在所难免的。看看这个文章
vue-cli3 取消关闭eslint 校验代码
setup() (重点)
setup() 是一个 新的生命周期函数
vue3专门给组件提供的新属性,它为我们使用vue3的 Composition API 新特性提供了统一的入口
- 执行时机
在beforeCreate之后,在create之前 - 参数
- 接收props数据
- context是一个上下文对象,这个上下文对象包含了一些有用的属性,这些属性在 vue 2.x 中需要通过this才能访问到,在 vue3.x 中,只需要如下访问就可以了
import {} from '@vue/composition-api'
export default {
setup(props,context) { // props 代表外界传入的属性
window.console.log("setup"); // 如果我们没有去掉代码检测,我们就得在console前面加个window
console.log(props.p1);
console.log(context.attrs);
},
props: {
p1: String // 声明
}
}
注意: setup() 里面无法获取this(其实是context代替了它)
reactive
reactive() 函数接收一个普通对象,返回一个响应对象,必须在 setup() 下面用
-
基本语法
- 按需导入reactive函数
import {reactive} from '@vue/composition-api'
- 创建 一个响应式数据对象
setup() { const state = reactive({count:0}); console.log(state); state.count+=1; // 反手加个1 console.log(state); return state },
这一步类似于我们之前的data()函数
然后我们就可以在 template中访问这个数据啦<template> <div> <p>count值为 {{count}}</p> <button @click="count+=1">+1</button> </div> </template>
ref(重点)
必须在 setup() 下面用
-
基本语法
ref() 函数用来根据给定的值创建一个响应式的数据对象,ref() 函数调用的返回值是一个对象,这个对象上只包含 .value 属性: -
在template中访问ref创建的响应式数据
<template> <div> <p>refCount的值为 {{refCount}}</p> <button @click="refCount+=1">+1</button> </div> </template> <script> import {ref} from '@vue/composition-api'; export default { setup() { const refCount = ref(0); console.log(refCount.value); return { refCount }; } } </script>
注意:当我们创建出来的 响应式对象 在setup中要取出数据的话就得 取它的 value 属性,但当我们return出来的时候,我们就不需要取它的属性了
-
在reactive对象中访问ref创建的响应式数据
当把 ref() 创建出来的响应式数据对象,挂载到 reactive() 上时,会自动把对象展开为原始的值,不需要 .value 就可以直接被访问到
const refCount = ref(0);
const state = reactive({
refCount
})
console.log(state.refCount); //输出0
state.refCount++
console.log(refCount.value); // 输出1
注意: 如果ref重名了,那么新的ref会覆盖旧的ref
const c1 = ref(0);
const state = reactive({
c1
})
// 再次创建 ref, 命名为 c2
const c2 = ref(9);
state.c1 = c2;
state.c1++;
console.log(state.c1);// 输出10
console.log(c2.value);// 输出10
console.log(c1.value);// 输出0
注意啦,这里有指针的概念,就是 原本 c1的地址 指向了 c2
isRef
用来判断某个值是否 ref() 创建出来的对象; 应用场景: 当需要展开某个可能为 ref() 创建出来的值的时候用到
import {isRef} from '@vue/composition-api'
const unwrapped = isRef(foo)? foo.value:foo;
toRefs
toRefs 函数可以将 reactive() 创建出来的响应式对象,转换为ref()类型的响应式数据。
我们先来说说reactive 函数的缺点
<template>
<div>
<p>count值为{{count}}</p>
<button @click="add">+1</button>
</div>
</template>
<script>
import {reactive} from "@vue/composition-api";
export default {
setup() {
const state = reactive({count:0,name: 'zs'});
// 定义自增+1的函数
// 函数最好也写进setup中
const add = () => {
state.count+=1;
}
return {
...state, // 通过这种方式return出去里面的值就固定了
add
};
}
}
</script>
此时我们改一改return部分的state 即可
return {
...toRefs(state), // 这样会把state里面的每一个属性都转化为ref
add
};
computed
computed() 用来创建计算属性,computed() 函数的返回值是一个 ref 的实例。使用 computed 之前需要导入
import {reactive, toRefs} from "@vue/composition-api";
创建只读的计算属性
注意,时刻记住 在setup函数里面 要去ref()对象的值需要用 .value 的方式取
const refCount = ref(0);
const computedCount = computed( ()=> refCount.value +1 );
return {
refCount,
computedCount // 此时 computedCount的值永远比上一个大1
};
创建可读可写的计算属性
在我们读数的时候,得到的结果会比原来的大 1 ,此时调用了get
在我们写数据的时候, 调用了set函数将 我们传入的数据-1 再赋值给count.value
const count = ref(1);
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val-1
}
})
plusOne.value = 9
console.log(count.value) //输出8
watch
watch() 函数用来监听某些数据项的
当然,咱先得导入
基本用法
const refCount = ref(0);
// watch默认情况下 组件在第一次创建的时候就执行了一次 如果不想它执行 就得传一个参数 {lazy:false}
watch(()=>console.log(refCount.value));
setTimeout(()=>{
refCount.value += 1;
},1500);
监听指定的数据源
监视 reactive类型的数据源:
const state = reactive({
count: 0
})
watch(()=>state.count,
(newVal,oldVal)=>{
console.log(newVal,oldVal)
},
{lazy:true}// 这里让组件刚创建的时候不要运行
);
监视 ref 类型的数据源:
const count = ref(0);
watch(count,(newVal,oldVal) => {
/*.....*/
})
监听多个数据源
监视 reactive类型的数据源:
const state = reactive({
count: 0,
name: 'zs'
})
watch([()=>state.count,()=>state.name],
([newCount,newName],[oldCount,oldName])=>{
console.log(newCount,newName)
console.log(oldCount,oldName)
},
{lazy:true}
);
setTimeout(()=>{
state.count += 1;
},1500);
setTimeout(()=>{
state.name += "帅气";
},3000);
监视 ref 类型的数据源:
参照单个的用法修改上面的代码就好了。
清除监试
在setup() 内创建watch监视,会在组件销毁的时候自动销毁。如果明确地停止某个参数,可以调用watch() 函数的返回值即可
const stop = watch(()=>{
/*...*/
})
stop()
在watch中清除无效的异步任务
有些时候,当贝watch监视的值发生改变时,或watch本身被stop之后,我们期望能够清除那些无效的异步任务,此时,watch回调函数中提供一个 cleanup registrator function 来执行清除的工作,这个清除函数会在如下情况下被调用:
- watch被重复调用
- watch 被强制stop了
例子
<template>
<div>
<input type="text" v-model="kw">
</div>
</template>
<script>
import {ref,watch} from "@vue/composition-api"
export default {
setup() {
const kw = ref("");
const asyncPrint = val => {
return setTimeout(()=>{
console.log(val);
},500);
};
watch(kw, (newVal,oldVal,clean)=> {
const timerId = asyncPrint(newVal);
clean(()=>clearTimeout(timerId)) //清除之前没问完成的异步任务
},{lazy:true});
return {
kw
};
}
}
</script>
解释一下:因为有些时候用户会按着键盘连续输入一些东西,如果我们对每个输入都进行ajax请求性能会很差,所以咱做个防抖,上面就是例子。
生命周期函数
先从黑马那边弄张图
当然使用之前我们还是要导入
说个题外话,在组件渲染的时候,我们尽量在mounted进行ajax请求
当我们定义生命周期函数的时候,有两种写法
- 像之前那样
setup() {
console.log("setup")
},
beforeMount() {
console.log("onBeforeMount");
},
mounted() {
console.log("onMounted");
}
- 写在setup函数里面
setup() {
onBeforeMount(()=>{
console.log("onBeforeMount");
})
onMounted(()=>{
console.log("onMounted");
})
}
只是写在setup函数里面前边要加一个on(官方推荐)
provide&inject
provide() 和 inject() 可以实现嵌套组件之间的数据传递。这两个函数只能在 setup() 函数中使用。父级组件中使用 provide() 函数向下传递数据; 子组件中使用 inject() 获取上层传递下来的数据(无论多少级)
共享普通数据
父组件
import ComSonSon from './09.sonson';
export default {
components: {
'com-sonson': ComSonSon
}
}
子组件
import {inject} from '@vue/composition-api'
export default {
setup() {
const color = inject('themeColor');
return {
color
};
}
}
共享 ref 响应式数据
传个ref数据就是了!!
template refs
通过 ref() 引用页面上的元素或组件
操作DOM
<template>
<div>
<h3 ref="h3Ref">h3ref</h3>
</div>
</template>
<script>
import { ref,onMounted } from '@vue/composition-api'
export default {
setup() {
//创建一个新的ref
const h3Ref = ref(null);
onMounted(() => {
console.log(h3Ref.value);
h3Ref.value.style.color = 'red';
})
return{
h3Ref
}
}
}
</script>
甚至还能操作组件的DOM
父组件
<template>
<div>
<com-son ref="comRef"/> // 在这里用ref指令绑定DOM
<button @click="showCom">打印 comRef的值</button>
</div>
</template>
<script>
import ComSon from './components/08.son'
import { provide ,ref } from '@vue/composition-api'
export default {
name: 'app',
components: {
'com-son': ComSon,
'com-refdom': ComRefDOM
},
setup() {
const comRef = ref(null)
const showCom = () => {
console.log(comRef);
console.log('str1的值是 ' + comRef.value.str1);
comRef.value.setStr();
}
return{
comRef,
showCom
}
}
}
</script>
<style>
</style>
子组件
<template>
<div>
<h2>子组件</h2>
<p>{{str1}}</p>
<hr>
</div>
</template>
<script>
import {ref} from '@vue/composition-api'
export default {
setup() {
const str1 = ref('this is 子组件')
const setStr = ()=> {
str1.value = '被赋值啦~~~'
}
return {
str1,
setStr
}
}
}
</script>
简单点说就是 setup 返回的ref响应式数据通过ref指令绑定DOM
createComponent
该函数不是必须的,除非你想完美结合TypeScript 提供的类型判断来进行项目的开发
这个函数仅仅提供了类型判断,能为setup() 中的props提供完整的类型判断
小结
vue3.0 相比之前更小更快更简便,数据绑定,对dom的操作也更加简单明了,按需导入,setup函数的出现对性能的提高十分明显。还有快速生成脚手架的优化,大大减轻了我们程序员的压力
以上内容综合了刘老师直播课的课程笔记所写