3.12.$nextTick
这是一个生命周期钩子
**this.$nextTick(回调函数)**在下一次DOM更新结束后执行其指定的回调
什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行
使用 $nextTick 优化 Todo-List
src/components/MyItem.vue
<template>
<li>
<label>
<!-- 如下代码也能实现功能,但是不太推荐,因为有点违反原则,因为修改了props -->
<!-- <input type="checkbox" v-model="todo.done"/> -->
<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)">
<span v-show="!todo.isEdit">{{todo.title}}</span>
<input
type="text"
v-show="todo.isEdit"
:value="todo.title"
@blur="handleBlur(todo, $event)"
ref="inputTitle"
/>
</label>
<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
<button v-show="!todo.isEdit" class="btn btn-edit" @click="handleEdit(todo)">编辑</button>
</li>
</template>
<script>
import pubsub from 'pubsub-js';
export default {
name: "Item",
// 声明接收todo
props:['todo'],
methods: {
// 勾选or取消勾选
handleCheck(id) {
// 通知App组件将对应的todo对象的done值取反
this.$bus.$emit('checkTodo',id);
},
// 删除
handleDelete(id){
if(confirm('确定删除吗?')) {
// 通知App组件将对应的todo对象删除
pubsub.publish('deleteTodo', id) // 发布消息
}
},
// 编辑
handleEdit(todo) {
// 判断是否有isEdit属性
if (todo.hasOwnProperty("isEdit")) {
todo.isEdit = true;
} else {
console.log("todo身上没有isEdit")
this.$set(todo, "isEdit", true);
}
// 在下一次DOM更新借宿后执行其指定的函数
this.$nextTick(function () {
this.$refs.inputTitle.focus();
});
},
// 失去焦点回调(真正执行修改逻辑)
handleBlur(todo, e) {
todo.isEdit = false;
if (!e.target.value.trim()) return alert("输入不能为空!");
console.log(todo.id, e.target.value);
this.$bus.$emit('updateTodo', todo.id, e.target.value);
}
}
}
</script>
3.13.过渡与动画
Vue封装的过度与动画:在插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名
写法
- 准备好样式
- 元素进入的样式
- **v-enter ** 进入的起点
- v-enter-active 进入过程中
- **v-enter-to ** 进入的终点
- 元素离开的样式
- **v-leave ** 离开的起点
- **v-leave-active ** 离开过程中
- v-leave-to 离开的终点
- 元素进入的样式
- 使用<transition>包裹要过度的元素,并配置name属性,此时需要将上面样式名的v换为name
- 要让页面一开始就显示动画,需要添加appear
<transition name="hello" appear> <h1 v-show="isShow">你好啊!</h1> </transition> <style> .hello-enter-active { animation: hello 0.5s linear; } .hello-leave-active { animation: hello 0.5s linear reverse; } @keyframes hello { from { transform: translateX(-100%); } to { transform: translateX(0px); } } </style>
- 备注:若有多个元素需要过度,则需要使用<transition-group>,且每个元素都要指定key值
<transition-group name="hello" appear> <h1 v-show="!isShow" key="1">你好啊!</h1> <h1 v-show="isShow" key="2">尚硅谷!</h1> </transition-group>
- 第三方动画库Animate.css
<transition-group appear name="animate__animated animate__bounce" enter-active-class="animate__swing" leave-active-class="animate__backOutUp"> <h1 v-show="!isShow" key="1">你好啊!</h1> <h1 v-show="isShow" key="2">尚硅谷!</h1> </transition-group>
src/App.vue
<template>
<div>
<Test/>
<Test2/>
<Test3/>
</div>
</template>
<script>
// 引入组件
import Test from './components/Test';
import Test2 from './components/Test2';
import Test3 from './components/Test3';
export default {
name:'App',
components: {
Test,
Test2,
Test3
}
}
</script>
src/components/test.vue
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<transition name="hello" appear>
<h1 v-show="isShow">你好啊!</h1>
</transition>
</div>
</template>
<script>
export default {
name: 'Test',
data() {
return {
isShow: true
}
}
}
</script>
<style scoped>
h1 {
background-color: orange;
}
.hello-enter-active {
animation: atguigu 0.5s linear;
}
.hello-leave-active {
animation: atguigu 0.5s linear reverse;
}
@keyframes atguigu {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0px);
}
}
</style>
src/components/test2
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<transition-group name="hello" appear>
<h1 v-show="!isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">尚硅谷!</h1>
</transition-group>
</div>
</template>
<script>
export default {
name: 'Test2',
data() {
return {
isShow: true
}
}
}
</script>
<style scoped>
h1 {
background-color: orange;
/* transition: 0.5s linear; */
}
/* 进入的起点、离开的终点 */
.hello-enter,.hello-leave-to {
transform: translateX(-100%);
}
.hello-enter-active,.hello-leave-active{
transition: 0.5s linear;
}
/* 进入的终点、离开的起点 */
.hello-enter-to,.hello-leave {
transform: translateX(0);
}
</style>
src/components/test3
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<transition-group
appear
name="animate__animated animate__bounce"
enter-active-class="animate__bounce"
leave-active-class="animate__backOutUp"
>
<h1 v-show="!isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">尚硅谷!</h1>
</transition-group>
</div>
</template>
<script>
import "animate.css";
export default {
name: 'Test3',
data() {
return {
isShow: true
}
}
}
</script>
<style scoped>
h1 {
background-color: orange;
/* transition: 0.5s linear; */
}
</style>
使用动画优化 Todo-List
src/components/MyList.vue
<template>
<ul class="todo-main">
<transition-group name="todo" appear>
<MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/>
</transition-group>
</ul>
</template>
<script>
import MyItem from './MyItem';
export default {
name: "List",
components: {
MyItem
},
props:['todos']
}
</script>
<style scoped>
.todo-main {
margin-left: 0px;
border: 1px solid #ddd;
border-radius: 2px;
padding: 0px;
}
.todo-empty {
height: 40px;
line-height: 40px;
border: 1px solid #ddd;
border-radius: 2px;
padding-left: 5px;
margin-top: 10px;
}
.todo-enter-active {
animation: liqb 0.5s linear;
}
.todo-leave-active {
animation: liqb 0.5s linear reverse;
}
@keyframes liqb {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0px);
}
}
</style>