多个根节点编辑器不会报错
Vue3 是容许咱们有多个根节点的,然而咱们前端培训如果应用 Vetur 就会报错,不会影响运行,然而看起来就很烦。所以当咱们转向 Volar 那么就不会呈现这个问题了。
编辑器分隔
即使 Vue 的组件化开发,能够将单文件的代码长度大幅缩短,但还是动辄几百行甚是上千行。那么咱们切换 template,script 和 style 的时候就要频繁高低翻,尽管有的插件能够间接定位到 css,然而你回不去啊!所以这个性能几乎是太人性化了。
装置完 Volar 当前,关上一个.vue 文件,看 vscode 的右上角,有这么一个图标,点一下。
它就会主动给你分隔成三个页面,别离对应 template,script 和 style,这样就太难受了有没有。
Vue 3 Snippets
举荐的第二个插件叫做 Vue 3 Snippets,同样的,他也有本人的 Vue2 版本。它是干什么的呢,能够看一下上面这张图,我只输出了“v3”,它有很多提醒,咱们就先抉择 v3computed,选中回车即可。
而后它就给主动给咱们写了如下代码
是不是超级省事,摸鱼的工夫又减少了!还有更多乏味的应用形式,小伙伴们自行摸索吧。
创立 Vue3 我的项目
那么正式开始学习咱们的 Vue3,先从创立我的项目开始。
应用 vue-cli 创立
输出上面的命令而后抉择配置项进行装置即可,这里留神 vue-cli 的版本肯定要在 4.5.0 以上
// 装置或者降级
npm install -g @vue/cli
// 查看版本 保障 vue cli 版本在 4.5.0 以上
vue –version
// 创立我的项目
vue create my-project
// 而后依据提醒一步一步傻瓜式操作就行了
…
复制代码
应用 Vite 创立
都说 Vue3.0 和 Vite2 更配,各种优化,各种快,但都不属于本文的内容,本文的目标咱们只须要晓得它特地好用,怎么用就行了。我这里是多抉择了 TS,每行都有正文,高深莫测。
// 初始化 viete 我的项目
npm init vite-app <project-name>
// 进入我的项目文件夹
cd <project-name>
// 装置依赖
npm install
// 启动我的项目
npm run dev
复制代码
创立完当前咱们先来看看入口文件 main.ts
// 引入 createApp 函数, 创立对应的利用, 产生利用的实例对象
import {createApp} from ‘vue’;
// 引入 app 组件(所有组件的父级组件)
import App from ‘./App.vue’;
// 创立 app 利用返回对应的实例对象, 调用 mount 办法进行挂载 挂载到 #app 节点下来
createApp(App).mount(‘#app’);
复制代码
而后看看根组件 app.vue
//Vue2 组件中的 html 模板中必须要有一对根标签,Vue3 组件的 html 模板中能够没有根标签
<template>
<img alt=”Vue logo” src=”./assets/logo.png”>
<!– 应用子级组件 –>
<HelloWorld msg=”Welcome to Your Vue.js + TypeScript App” />
</template>
<script lang=”ts”>
// 这里能够书写 TS 代码
// defineComponent 函数, 目标是定义一个组件 外部能够传入一个配置对象
import {defineComponent} from ‘vue’;
// 引入子级组件
import HelloWorld from ‘./components/HelloWorld.vue’;
// 裸露进来一个定义好的组件
export default defineComponent({
// 以后组件的名字
name: ‘App’,
// 注册组件
components: {
// 注册一个子级组件
HelloWorld,
},
});
</script>
复制代码
Composition API
接下来到了重头戏,Vue3 的招牌个性,Composition API
对于 Composition API 这里有大佬做的动画演示,极力推荐。
那个忙了一夜的 Vue3 动画很好,就是太短了
Composition API 能够更不便的抽取共通逻辑,然而不要过于在意逻辑代码复用,以性能提取代码也是一种思路。
顺便提一句,Vue3 兼容大部分 Vue2 语法,所以在 Vue3 中书写 Vue2 语法是没有问题的(破除的除外),然而既然咱们曾经降级 Vue3 了,不倡议混合应用,除非一些大型非凡我的项目须要兼容两个版本。
setup
setup 是组合 Composition API 中的入口函数,也是第一个要应用的函数。
setup 只在初始化时执行一次,所有的 Composition API 函数都在此应用。
setup() {
console.log(‘ 我执行了 ’) // 我执行了
},
复制代码
能够通过 console.log 看到 setup 是在 beforeCreate 生命周期之前执行的(只执行一次)
beforeCreate() {
console.log('beforeCreate 执行了');
},
setup() {
console.log('setup 执行了');
return {};
},
//setup 执行了
//beforeCreate 执行了
复制代码
由此能够推断出 setup 执行的时候, 组件对象还没有创立, 组件实例对象 this 还不可用, 此时 this 是 undefined, 不能通过 this 来拜访 data/computed/methods/props。
返回对象中的属性会与 data 函数返回对象的属性合并成为组件对象的属性,返回对象中的办法会与 methods 中的办法合并胜利组件对象的办法,如果有重名, setup 优先。因为在 setup 中 this 不可用,methods 中能够拜访 setup 提供的属性和办法, 但在 setup 办法中不能拜访 data 和 methods 里的内容,所以还是不倡议混合应用。
setup 函数如果返回对象, 对象中的 属性 或 办法 , 模板 中能够间接应用
//templete
<div>{{number}}</div>
//JS
setup() {
const number = 18;
return {
number,
};
},
复制代码
留神:setup 不能是一个 async 函数: 因为返回值不再是 return 的对象, 而是 promise, 模板中就不能够应用 return 中返回对象的数据了。
setup 的参数(props,context)`
props: 是一个对象, 外面有父级组件向子级组件传递的数据, 并且是在子级组件中应用 props 接管到的所有的属性
context:上下文对象,能够通过 es6 语法解构 setup(props, {attrs, slots, emit})
attrs: 获取以后组件标签上所有没有通过 props 接管的属性的对象, 相当于 this.$attrs
slots: 蕴含所有传入的插槽内容的对象, 相当于 this.$slots
emit: 用来散发自定义事件的函数, 相当于 this.$emit
演示 attrs 和 props
// 父组件
<template>
<child :msg=”msg” msg2=’ 哈哈哈 ’ />
</template>
<script lang=’ts’>
import {defineComponent, ref} from ‘vue’;
// 引入子组件
import Child from ‘./components/Child.vue’;
export default defineComponent({
name: ‘App’,
components: {
Child,
},
setup() {
const msg = ref('hello,vue3');
return {msg,};
},
});
</script>
// 子组件
<template>
<h2> 子组件 </h2>
<h3>msg:{{msg}}</h3>
</template>
<script lang=’ts’>
import {defineComponent} from ‘vue’;
export default defineComponent({
name: ‘Child’,
props: [‘msg’],
setup(props, {attrs, slots, emit}) {
console.log('props:', props);//msg: "hello,vue3"
console.log('attrs:', attrs);//msg2: "哈哈哈"
return {};
},
});
</script>
复制代码
演示 emit
// 父组件
<template>
<child @show=”show” />
</template>
<script lang=’ts’>
setup() {
const show = () => {console.log('name:', 'hzw');
};
return {show,};
},
</script>
// 子组件
<template>
<button @click=’emitFn’> 事件散发 </button>
</template>
<script lang=’ts’>
import {defineComponent} from ‘vue’;
export default defineComponent({
name: ‘Child’,
setup(props, { emit}) {
const emitFn = () => {emit('show');
};
return {emitFn,};
},
});
</script>
复制代码
ref
作用
定义一个响应式的数据(个别用来定义一个根本类型的响应式数据 Undefined、Null、Boolean、Number 和 String)
语法
const xxx = ref(initValue):
复制代码
留神:script 中操作数据须要应用 xxx.value 的模式,而模板中不须要增加.value
用一个例子来演示:实现一个按钮, 点击能够减少数字
<template>
<div>{{count}}</div>
<button @click=’updateCount’> 减少 </button>
</template>
复制代码
在 Vue2 中
data() {
return {
conunt: 0,
};
},
methods: {
updateCount() {
this.conunt++;
},
},
复制代码
在 Vue3 中
setup() {
// ref 用于定义一个响应式的数据,返回的是一个 Ref 对象,对象中有一个 value 属性
// 如果须要对数据进行操作,须要应用该 Ref 对象的 value 属性
const count = ref(0);
function updateCount() {count.value++;}
return {
count,
updateCount,
};
},
复制代码
在 Vue2 中咱们通过 this.$refs 来获取 dom 节点,Vue3 中咱们通过 ref 来获取节点
首先须要在标签上增加 ref=’xxx’,而后再 setup 中定义一个初始值为 null 的 ref 类型, 名字要和标签的 ref 属性统一
const xxx = ref(null)
复制代码
留神:肯定要在 setup 的 return 中返回,不然会报错。
还是用一个例子来演示: 让输入框主动获取焦点
<template>
<h2>App</h2>
<input type=”text”>—
<input type=”text” ref=”inputRef”>
</template>
<script lang=”ts”>
import {onMounted, ref} from ‘vue’
/*
ref 获取元素: 利用 ref 函数获取组件中的标签元素
性能需要: 让输入框主动获取焦点
*/
export default {
setup() {
const inputRef = ref<HTMLElement|null>(null)
onMounted(() => {inputRef.value && inputRef.value.focus()
})
return {inputRef}
},
}
</script>
复制代码
reactive
语法
const proxy = reactive(obj)
复制代码
作用
定义多个数据的响应式,接管一个一般对象而后返回该一般对象的响应式代理器对象(Proxy),响应式转换是“深层的”:会影响对象外部所有嵌套的属性, 所有的数据都是响应式的。
代码演示
<template>
<h3> 姓名:{{user.name}}</h3>
<h3> 年龄:{{user.age}}</h3>
<h3>wife:{{user.wife}}</h3>
<button @click=”updateUser”> 更新 </button>
</template>
setup() {
const user = reactive({
name: 'hzw',
age: 18,
wife: {
name: 'xioaohong',
age: 18,
books: ['红宝书', '设计模式', '算法与数据结构'],
},
});
const updateUser = () => {
user.name = '小红';
user.age += 2;
user.wife.books[0] = '金瓶梅';
};
return {
user,
updateUser,
};
},
复制代码
computed 函数:
与 Vue2 中的 computed 配置性能统一,返回的是一个 ref 类型的对象
计算属性的函数中如果只传入一个回调函数 示意的是 get 操作
import {computed} from ‘vue’;
const user = reactive({
firstName: ‘ 韩 ’,
lastName: ‘ 志伟 ’,
});
const fullName1 = computed(() => {
return user.firstName + user.lastName;
});
return {
user,
fullName1,
};
复制代码
计算属性的函数中能够传入一个对象, 能够蕴含 set 和 get 函数, 进行读取和批改的操作
const fullName2 = computed({
get() {
return user.firstName + '_' + user.lastName;
},
set(val: string) {
const names = val.split('_');
user.firstName = names[0];
user.lastName = names[1];
},
});
return {
user,
fullName2,
};
复制代码
watch 函数:
与 Vue2 中的 watch 配置性能统一,
参数 1: 要监听的数据
参数 2: 回调函数
参数 3: 配置
作用
监督指定的一个或多个响应式数据, 一旦数据变动, 就主动执行监督回调
默认初始时不执行回调, 但能够通过配置 immediate 为 true, 来指定初始时立刻执行第一次
通过配置 deep 为 true, 来指定深度监督
import {watch, ref} from ‘vue’;
const user = reactive({
firstName: ‘ 韩 ’,
lastName: ‘ 志伟 ’,
});
const fullName3 = ref(”);
watch(
user,
({firstName, lastName}) => {
fullName3.value = firstName + '_' + lastName;
},
{immediate: true, deep: true}
);
return {
user,
fullName3,
};
复制代码
watch 监听多个数据, 应用数组
watch 监听非响应式数据的时候须要应用回调函数的模式
watch([()=>user.firstName,()=>user.lastName,fullName3],()=>{console.log(‘ 我执行了 ’)})
复制代码
watchEffect 函数:
作用
监督数据发生变化时执行回调,不必间接指定要监督的数据, 回调函数中应用的哪些响应式数据就监督哪些响应式数据,默认初始时就会执行第一次, 从而能够收集须要监督的数据。
import {watchEffect, ref} from ‘vue’;
const user = reactive({
firstName: ‘ 韩 ’,
lastName: ‘ 志伟 ’,
});
const fullName4 = ref(”);
watchEffect(() => {
fullName4.value = user.firstName + ‘_’ + user.lastName;
});
return {
user,
fullName4,
};
watchEffect 能够实现计算属性 set 办法
watchEffect(() => {
const names = fullName3.value.split('_');
user.firstName = names[0];
user.lastName = names[1];
});
复制代码
生命周期比照:
留神:3.0 中的生命周期钩子要比 2.X 中雷同生命周期的钩子要快
Composition API 还新增了以下调试钩子函数:然而不怎么罕用
onRenderTracked
onRenderTriggered
代码演示
setup() {
onBeforeMount(() => {
console.log('--onBeforeMount')
})
onMounted(() => {
console.log('--onMounted')
})
onBeforeUpdate(() => {
console.log('--onBeforeUpdate')
})
onUpdated(() => {
console.log('--onUpdated')
})
onBeforeUnmount(() => {
console.log('--onBeforeUnmount')
})
onUnmounted(() => {
console.log('--onUnmounted')
})
}
复制代码
toRefs
作用
把一个响应式对象转换成一般对象,该一般对象的每个属性都是一个 ref
利用
咱们应用 reactive 创立的对象,如果想在模板中应用,就必须得应用 xxx.xxx 的模式, 如果大量用到的话还是很麻烦的, 然而应用 es6 解构当前, 会失去响应式, 那么 toRefs 的作用就体现在这,,利用 toRefs 能够将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性。当然小伙伴们能够自行开发更多利用场景。
代码演示
<template>
<div>
name:{{name}}
</div>
</template>
<script lang=’ts’>
import {defineComponent, reactive, toRefs} from ‘vue’;
export default defineComponent({
name: ”,
setup() {
const state = reactive({name: 'hzw',});
const state2 = toRefs(state);
setInterval(() => {state.name += '===';}, 1000);
return {
// 通过 toRefs 返回的对象, 解构进去的属性也是响应式的
...state2,
};
},
});
</script>
复制代码
provide 与 inject
作用
实现跨层级组件 (祖孙) 间通信
代码演示
父组件
<template>
<h1> 父组件 </h1>
<p> 以后色彩: {{color}}</p>
<button @click=”color=’red'”> 红 </button>
<button @click=”color=’yellow'”> 黄 </button>
<button @click=”color=’blue'”> 蓝 </button>
<Son />
</template>
<script lang=”ts”>
import {provide, ref} from ‘vue’
import Son from ‘./Son.vue’
export default {
name: ‘ProvideInject’,
components: {
Son
},
setup() {
const color = ref('red')
provide('color', color)
return {color}
}
}
</script>
复制代码
子组件
<template>
<div>
<h2> 子组件 </h2>
<hr>
<GrandSon />
</div>
</template>
<script lang=”ts”>
import GrandSon from ‘./GrandSon.vue’
export default {
components: {
GrandSon
},
}
</script>
复制代码
孙子组件
<template>
<h3 :style=”{color}”> 孙子组件: {{color}}</h3>
</template>
<script lang=”ts”>
import {inject} from ‘vue’
export default {
setup() {
const color = inject('color')
return {color}
}
}
</script>
复制代码
其余个性
**Teleport(瞬移)
作用 **
Teleport 提供了一种洁净的办法, 让组件的 html 在父组件界面外的特定标签 (很可能是 body) 下插入显示 换句话说就是能够把 子组件 或者 dom 节点 插入到任何你想插入到的中央去。
语法
应用 to 属性 引号内应用选择器
<teleport to=”body”>
</teleport>
复制代码
代码演示
// 父组件
<template>
<div >
<h2>App</h2>
<modal-button></modal-button>
</div>
</template>
<script lang=”ts”>
import ModalButton from ‘./components/ModalButton.vue’
export default {
setup() {
return {}
},
components: {
ModalButton,
},
}
</script>
// 子组件
<template>
<div >
<button @click="modalOpen = true">
点我关上对话框
</button>
<teleport to="body">
<div v-if="modalOpen"
>
看看我呈现在了哪里
<button @click="modalOpen = false">
Close
</button>
</div>
</teleport>
</div>
</template>
<script>
import {ref} from ‘vue’
export default {
name: ‘modal-button’,
setup() {
const modalOpen = ref(false)
return {modalOpen,}
},
}
</script>
复制代码
能够看到在子组件中的 looklook 元素跑到了 body 上面, 而之前的地位默认呈现了两行正文
微信截图_20210623170701.png
Suspense(不确定的)
作用
它们容许咱们的应用程序在期待异步组件时渲染一些后备内容,能够让咱们创立一个平滑的用户体验
语法
<Suspense>
<template v-slot:default>
<!-- 异步组件 -->
<AsyncComp />
</template>
<template v-slot:fallback>
<!-- 后备内容 -->
<h1>LOADING...</h1>
</template>
</Suspense>
复制代码
vue3 中引入异步组件的形式
const AsyncComp = defineAsyncComponent(() => import(‘./AsyncComp.vue’))
复制代码
代码演示
父组件
<template>
<Suspense>
<!-- v-slot:defaul 能够简写成 #defaul -->
<template v-slot:default>
<AsyncComp/>
</template>
<template v-slot:fallback>
<h1>LOADING...</h1>
</template>
</Suspense>
</template>
<script lang=”ts”>
import {defineAsyncComponent} from ‘vue’
const AsyncComp = defineAsyncComponent(() => import(‘./AsyncComp.vue’))
export default {
setup() {
return {}
},
components: {
AsyncComp,
}
}
</script>
复制代码
子组件
<template>
<h2>AsyncComp22</h2>
<p>{{msg}}</p>
</template>
<script lang=”ts”>
export default {
name: ‘AsyncComp’,
setup () {
return new Promise((resolve, reject) => {setTimeout(() => {
resolve({msg: 'abc'})
}, 2000)
})
}
}
</script>
复制代码
通过下图能够看到在异步组件加载进去之前, 显示的是 fallback 中的内容
响应式数据的判断
作用
isRef: 查看一个值是否为一个 ref 对象
isReactive: 查看一个对象是否是由 reactive 创立的响应式代理
isReadonly: 查看一个对象是否是由 readonly 创立的只读代理
isProxy: 查看一个对象是否是由 reactive 或者 readonly 办法创立的代理
代码演示
setup() {
const state1 = ref(1);
console.log('isref:', isRef(state1));//isref: true
const state2 = reactive({});
console.log('isReactive:', isReactive(state2));//isReactive: true
const state3 = readonly({});
console.log('isReadonly:', isReadonly(state3));//isReadonly: true
const state4 = reactive({});
console.log('isProxy:', isProxy(state2));//isProxy: true
console.log('isProxy:', isProxy(state4));//isProxy: true
return {};
},
复制代码
其余不罕用个性
还有很多很多不罕用的新个性,我在日常开发中是没有用到的,很多都是用来做优化的,感兴趣的小伙伴们自行去官网查看,或者大佬们能够介绍一下利用场景。
shallowReactive
shallowRef
readonly
shallowReadonly
markRaw
customRef
…
语法糖
尽管 Composition API 用起来曾经十分不便了,然而咱们还是有很烦的中央,比方
组件引入了还要注册
属性和办法都要在 setup 函数中返回,有的时候仅一个 return 就十几行甚至几十行
…
不想写啊怎么办
好办,Vue3 官网提供了 script setup 语法糖
只须要在 script 标签中增加 setup,组件只需引入不必注册,属性和办法也不必返回,setup 函数也不须要,甚至 export default 都不必写了,不仅是数据,计算属性和办法,甚至是自定义指令也能够在咱们的 template 中主动取得。
然而这么过瘾的语法糖,还是略微增加了一点点心智累赘,因为没有了 setup 函数,那么 props,emit,attrs 怎么获取呢,就要介绍一下新的语法了。
setup script 语法糖提供了三个新的 API 来供咱们应用:defineProps、defineEmit 和 useContext
defineProps 用来接管父组件传来的值 props。
defineEmit 用来申明触发的事件表。
useContext 用来获取组件上下文 context。
代码演示
父组件
<template>
<div>
<h2> 我是父组件!</h2>
<Child msg="hello"
@child-click="handleClick" />
</div>
</template>
<script setup>
import Child from ‘./components/Child.vue’
const handleClick = (ctx) => {
console.log(ctx)
}
</script>
复制代码
子组件
<template>
<span @click=”sonClick”>msg: {{props.msg}}</span>
</template>
<script setup>
import {useContext, defineProps, defineEmit} from ‘vue’
const emit = defineEmit([‘child-click’])
const ctx = useContext()
const props = defineProps({
msg: String,
})
const sonClick = () => {
emit(‘child-click’, ctx)
}
</script>
复制代码
咱们点击一下子组件
能够看到 context 被打印了进去,其中的 attrs、emit、slots、expose 属性和办法仍然能够应用。props 也能够输入在页面上,事件也胜利派发。
其余知识点
接下来介绍一下我应用 Vue3 过程中遇到的问题或者小技巧,不全面,想起什么就写什么吧
script setup 语法糖请留神
如果在父组件中通过 ref=’xxx’ 的办法来获取子组件实例,子组件应用了 script setup 语法糖, 那么子组件的数据须要用 expose 的形式导出,否则会因为获取不到数据而报错。
代码演示
父组件
<template>
<div>
<h2> 我是父组件!</h2>
<Child ref='son' />
</div>
</template>
<script setup>
import Child from ‘./components/Child.vue’
import {ref} from ‘vue’
const son = ref(null)
console.log(‘🚀🚀~ son:’, son)
</script>
复制代码
子组件先不应用语法糖
<template>
<div>
我是子组件{{msg}}
</div>
</template>
<script >
import {ref} from ‘vue’
export default {
setup() {
const msg = ref('hello')
return {msg,}
},
}
复制代码
能够看到是能够获取到咱们在子组件中定义的 msg 属性的
当初把子组件换成 script setup 语法糖再来试一试
<template>
<div>
我是子组件{{msg}}
</div>
</template>
<script setup>
import {ref} from ‘vue’
const msg = ref(‘hello’)
</script>
复制代码
能够看到当初是获取不到子组件定义的 msg 属性的
Emit 派发事件能够对参数进行验证
父组件
<template>
<div>
<h2> 我是父组件!</h2>
<Child @sonClick='sonClick' />
</div>
</template>
<script setup>
import Child from ‘./components/Child.vue’
import {ref} from ‘vue’
const sonClick = (value) => {
console.log(value)
}
</script>
复制代码
子组件
<template>
<div>
我是子组件{{msg}}
</div>
<button @click=”handleClick(1)”> 我是按钮 1 </button>
<button @click=”handleClick(2)”> 我是按钮 2 </button>
</template>
<script>
import {ref} from ‘vue’
export default {
name: ”,
emits: {
sonClick: (value) => {if (value === 1) {return true} else {return false}
},
},
setup(props, { emit}) {
const msg = ref('hello')
const handleClick = (value) => {emit('sonClick', value)
}
return {
msg,
handleClick,
}
},
}
</script>
复制代码
咱们别离点一下按钮 1 和按钮 2,能够看到当咱们点了按钮 2 的时候,控制台会收回正告,然而程序会继续执行,还没想到什么适宜的利用场景,然而要晓得这个知识点,小伙伴们能够在这搞事件。
跨组件通信 mitt.js
Vue2 中怎么实现跨组件通信呢, 很多人第一想法就是 event bus。然而 Vue3 移除了 $on,$once,$off 导致不能应用这个办法。然而 Vue 官网给大家举荐了 mitt.js, 它的原理就是 event bus。
代码演示
先装置
npm i mitt -s
复制代码
而后封装一个 hook
//mitt.js
import mitt from ‘mitt’
const emitter = mitt();
export default emitter;
复制代码
父组件
<template>
<div>
<h2> 我是父组件!</h2>
<Child1 />
<Child2 />
</div>
</template>
<script setup>
import Child1 from ‘./components/Child1.vue’
import Child2 from ‘./components/Child2.vue’
</script>
复制代码
子组件 1
<template>
<div>
我是子组件 1
<h1>{{msg}}</h1>
</div>
</template>
<script>
import {ref, onUnmounted} from ‘vue’
import emitter from ‘../mitt’
export default {
name: ”,
setup() {
// 初始化
const msg = ref('hello')
const changeMsg = () => {msg.value = 'world'}
// 监听事件, 更新数据
emitter.on('change-msg', changeMsg)
// 显式卸载
onUnmounted(() => {emitter.off('change-msg', changeMsg)
})
return {
msg,
changeMsg,
}
},
}
</script>
复制代码
子组件 2
<template>
<div>
我是子组件 2
</div>
<button @click=’changeMsg’> 点击批改 msg</button>
</template>
<script>
import {ref} from ‘vue’
import emitter from ‘../mitt’
export default {
name: ”,
setup() {
const changeMsg = () => {emitter.emit('change-msg')
}
return {changeMsg,}
},
}
</script>
复制代码
自定义指令
先看看 Vue2 自定义指令的钩子
bind:当指令绑定在对应元素时触发。只会触发一次。
inserted:当对应元素被插入到 DOM 的父元素时触发。
update:当元素更新时,这个钩子会被触发(此时元素的后辈元素还没有触发更新)。
componentUpdated:当整个组件(包含子组件)实现更新后,这个钩子触发。
unbind:当指令被从元素上移除时,这个钩子会被触发。也只触发一次。
在 Vue3 中,官网为了更有助于代码的可读性和格调对立,把自定义指令的钩子名称改的更像是组件生命周期,只管他们是两回事
bind => beforeMount
inserted => mounted
beforeUpdate: 新的钩子,会在元素本身更新前触发
update => 移除!
componentUpdated => updated
beforeUnmount: 新的钩子,当元素本身被卸载前触发
unbind => unmounted
过渡动画
这个没有什么大的改变,只是批改了两个 class 名字,正是因为没有什么大的改变,导致我已经在这里栽了大跟头,写完了怎么都不对,起初查官网才晓得。
以下是间接援用 官网的原文
v-enter-from:定义进入过渡的开始状态。在元素被插入之前失效,在元素被插入之后的下一帧移除。
v-enter-active:定义进入过渡失效时的状态。在整个进入过渡的阶段中利用,在元素被插入之前失效,在过渡 / 动画实现之后移除。这个类能够被用来定义进入过渡的过程工夫,提早和曲线函数。
v-enter-to:定义进入过渡的完结状态。在元素被插入之后下一帧失效 (与此同时 v-enter-from 被移除),在过渡 / 动画实现之后移除。
v-leave-from:定义来到过渡的开始状态。在来到过渡被触发时立即失效,下一帧被移除。
v-leave-active:定义来到过渡失效时的状态。在整个来到过渡的阶段中利用,在来到过渡被触发时立即失效,在过渡 / 动画实现之后移除。这个类能够被用来定义来到过渡的过程工夫,提早和曲线函数。
v-leave-to:来到过渡的完结状态。在来到过渡被触发之后下一帧失效 (与此同时 v-leave-from 被删除),在过渡 / 动画实现之后移除。
特地留神的是 v -enter 改成了 v -enter-form,v-leave 改成了 v -leave-from。