对vue3 新增的api 称为 composition API, 同时也保留了大部分vue2的api称为 options API
对vue3的初步使用最直观的体验就是几乎没有看见this的身影,其次就是纯函数式的写法带来的快感
首先创建vue3的项目,可以用vue-cli 中的 vue create xxx 去创建,模版直接选用vue3即可
先看看 main.js 文件
// vue3版
import { createApp } from "vue";
import App from "./App.vue";
createApp(App).mount("#app");
// vue2版
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
tree-shaking —————— vue3减少了实例这个操作,这个只是优化了用户的体验,关键在于对vue的引入,在vue2版本中,vue是整个引入的,这对最后的项目打包时是占有固定的体积的,vue3在这方面看出来做了优化,通过“按需引入”的概念进行引入,这便可以初步控制打包的大小
App.vue
// vue3版
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
</template>
// vue2版
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
这里明显看到对根结点有做不一样的处理,通过翻阅官方文档了解到 vue3中对fragment
接着又发现一个有意思的 composition API ———— teleport 我先文字描述一下一个经常使用的业务场景,就是在后台管理系统中常常会有弹框在组件生态中叫模态框,那vue2中的实现由于实例中都是加载中根元素app下,如果app的添加了position:relative;此样式,那么模态框就会以app来做相对参照物去进行位移,所以在vue2要特别注意根元素的样式设置; 那么在vue3中提供了teleport 这个api去避免这个问题,说白了就是模态框这个组件创建在了根元素外的结点,并没有在根元素里面,所以即使根元素有相关的样式变更也不受影响
使用方法就是用teleport当作标签 并在to属性中表明所要创建在那个标签下
const app = Vue.createApp({});
app.component('modal-button', {
template: `
<button @click="modalOpen = true">
Open full screen modal! (With teleport!)
</button>
<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleported modal!
(My parent is "body")
<button @click="modalOpen = false">
Close
</button>
</div>
</div>
</teleport>
`,
data() {
return {
modalOpen: false
}
}
})
app.mount('#app')
接下来进入常用的 composition API
setup ———— 可以理解为几乎所有逻辑行为定义都可以往这里加
ref ———— 创建响应式对象 通过创建ref 如果创建的是引用类型的 其实就是创建的ref对象中使用用了proxy代理
<template>
<div>
{{count}}
<button @click="handleCount">click<button/>
</div>
</template>
<script>
import { ref } from "vue"
export default {
setup() {
// 创建响应式对象
let count = ref(1);
// 更改count事件
function handleCount() {
count.value++;
}
// 暴露响应式数据 与 定义的方法
return {
count,
handleCount
}
}
}
reactive ———— 创建响应式对象 通过Proxy 代理
<template>
<div>
{{countObj.name}}:{{countObj.count}}
<button @click="handleCount">click<button/>
</div>
</template>
<script>
import { ref } from "vue"
export default {
setup() {
// 创建响应式对象
let countObj = reactive({
name:"xx"
count:1
});
// 更改count事件
function handleCount() {
countObj.count++;
}
// 暴露响应式数据 与 定义的方法
return {
countObj,
handleCount
}
}
}
readonly ———— 创建一个不可修改的响应式对象 与上述创建语法一致 props ———— 父子组件传值
<template>
<div>
child
</div>
</template>
<script>
import { ref } from "vue"
export default {
props:['title']
setup(props) {
// props 就是title就是在父组件中的属性,props即可接收到 注意props中不可修改
}
}
computed watch 实际上都变成了函数式的调用方式
<template>
<div>
child
</div>
</template>
<script>
import { ref } from "vue"
export default {
setup() {
let count = ref(1);
let double = computed(()=>{
return count.value * 2
})
// 需要监听的数据,回调函数,其它可设置参数
watch(count, (newVal, oldVal) => {
// todo soming
},{
immediate:true,
})
const user = reactive({
use:"xx",
age:18
})
// 引用类型某个属性
watch(() => user.age, (newVal, oldVal) => {
// todo soming
},{
immediate:true,
})
// 如果监听整个对象 需要对这个对象进行深克隆,不然无法响应 这里deepclone可以自己实现可以使用loadsh库等深克隆的方法
watch(()=> deepclone(user),(newVal, oldVal) => {
// todo soming
})
}
}
watchEffect ———— 跟watch使用大致相同,但无需具体指定监听谁
watchEffect((onInvalidate)=>{
onInvalidate(()=>{
// 在watchEffect被调用时会触发,使用组件被销毁时也会触发
})
// 在这里进行依赖收集,如果收集的依赖中有发生值的改变则会触发
},{
flush:"pre" // 默认值为pre 在组件render之前调用,post 在组件render之后调用
})
provide , inject ———— 依赖注入 设置值的组件
provide('属性名','属性值')
获取值的组件中
inject('属性名','默认值')