一、 vue
(1) 过渡
我们学习v-show指令和v-if指令,这些指令可以显示隐藏元素或者创建删除元素。vue允许我们在显示隐藏元素以及创建删除元素过程中,添加过渡效果。
transition元素(组件)是由vue提供的。可以为内部的元素添加过渡效果。
通过name属性设置过渡名称,之后就会根据该名称创建六个类,
例如 name=”dzx”
表示显示的过程(由隐藏的状态变成显示的状态).dzx-enter .dzx-enter-to .dzx-enter-active
表示隐藏的过程(由显示状态变成隐藏的状态).dzx-leave .dzx-leave-to .dzx-leave-active
我们基于这六个类,实现css过渡或者动画(借助于css3实现的)
01 transition.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<p><button @click="switchData">切换</button></p>
<transition name="demo">
<!-- 这里用 v-if 和 v-show 都可以 -->
<div class="item" v-show="isShow"></div>
</transition>
</div>
<script src="./dist/16.js"></script>
</body>
</html>
01 transition.js
import Vue from 'vue';
import './guodu.scss';
let app = new Vue({
el:"#app",
data:{
isShow:true
},
methods:{
switchData(){
this.isShow = !this.isShow
}
}
})
guodu.scss
.item{
width: 200px;
height: 200px;
background-color: pink;
}
// 动画实现
// 定义显示和隐藏的动画
// @keyframes toggle{
// form{
// width: 200px;
// height: 200px;
// opacity: 1;
// }
// to{
// width: 0;
// height: 0;
// opacity: 0;
// }
// }
// // 隐藏
// .demo-leave-active{
// animation: toggle 1s ;
// }
// // 显示
// .demo-enter-active{
// animation: toggle 1s reverse
// }
// 过渡实现
// 隐藏
.demo-enter,
.demo-leave-to{
width: 0;
height: 0;
opacity: 0;
}
// 注意 这一如果在上面定义了 例如 :item 样式
// 本样式可以不用写
// 显示
// .demo-enter-to,
// .demo-leave{
// width: 200px;
// height: 200px;
// opacity: 1;
// }
// 过程添加过度
.demo-enter-active,
.demo-leave-active{
transition: all 1s;
}
效果图
1.1 入场过渡
我们通过为transition组件添加appear属性,实现入场过渡:当元素加载的时候,执行动画。
1.2 过渡事件
css3过渡和动画有事件,我们可以通过DOM监听到。
过渡事件:webkitTransitionStart,webkitTransitionEnd
动画事件:webkitAnimationStart, webkitAnimationEnd
vue实现的过渡也可以监听动画开始与结束的事件,
显示过程
before-enter:处于隐藏状态;after-enter:处于显示状态;enter:显示过程
隐藏过程
before-leave:处于显示状态;after-leave:处于隐藏状态;leave:隐藏过程
我们可以通过v-on指令或者是@语法糖来监听这些事件
02 入场过渡 + 过渡过程.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<button @click="target">体验过度</button>
<transition
name="demo" appear
@before-enter="beforeEnter"
@after-enter="afterEnter"
@enter = "enter"
@before-leave="beforeLeave"
@after-leave = "afterLeave"
@leave = "leave"
>
<div class="item" v-show="isShow">
</transition>
</div>
</div>
<script src="./dist/17.js"></script>
</body>
</html>
02 入场过渡 + 过渡过程.js
import Vue from 'vue';
import './guodu.scss';
let app = new Vue({
el:"#app",
data:{
isShow:true
},
methods:{
target(){
this.isShow = !this.isShow
},
// 显示前
beforeEnter(){
console.log(1111,"beforeEnter");
},
// 显示后
afterEnter(){
console.log(222,"afterEnter");
},
// 显示过程
enter(){
console.log(333,"enter");
},
// 隐藏前
beforeLeave(){
console.log(4444,"beforeLeave");
},
// 隐藏后
afterLeave(){
console.log(5555,"afterLeave");
},
// 隐藏过程
leave(){
console.log(666,"leave");
}
}
})
效果图
1.3 多元素过渡
我们可以在transition中,定义多个元素,实现多个元素之间的过渡。
内部的元素必须设置key属性,属性值是唯一的。
我们通过mode属性定义切换模式:
in-out 新元素先执行,再执行当前的元素
out-in 当前的元素先执行,再执行新元素。
默认两个元素同时执行。
03 多元素同时执行.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<button @click="toggle">切换元素</button>
<!-- 通过 name 定义名称 -->
<!-- 通过 mode 属性,改变运行顺序 -->
<!-- in-out 先运行新的 -->
<!-- out-in 新的后执行 -->
<transition
name="demo"
appear
mode="out-in"
>
<div class="item1" v-if="isShow" key="1"></div>
<div class="item2" v-else key="2"></div>
</transition>
</div>
<script src="./dist/18.js"></script>
</body>
</html>
03 多元素同时执行.js
import Vue from 'vue';
import './duoyuansu.scss';
let app = new Vue({
el:"#app",
data:{
isShow:true
},
methods:{
toggle(){
this.isShow=!this.isShow
}
}
})
duoyuansu.scss
.item1{
width: 200px;
height: 200px;
background-color: blue;
}
.item2{
width: 200px;
height: 200px;
background-color: red;
}
// 隐藏
.demo-enter,
.demo-leave-to{
width: 0;
height: 0;
opacity: 0;
}
// 显示
// .demo-enter-to,
// .demo-leave{
// width: 200px;
// height: 200px;
// background-color: pink;
// }
// 过程添加过渡
.demo-enter-active,
.demo-leave-active{
transition: all 1s;
}
效果图
1.4 列表过渡
我们通过v-for指令渲染列表。
使用v-for指令创建列表元素的时候,如果需要过渡,要使用transition-group组件。
与transition组件的区别是:transition-group会渲染成一个真实的元素,
默认是span,通过tag属性可以自定义渲染的结果。
使用列表过渡的时候,每一个元素都要添加一个值是唯一的并且稳定的key属性。
transition与transition-group的区别:
transition 控制一个元素
transition-group 控制多个元素
1.5 关于列表过渡的案例
① 列表过渡
01 列表过渡.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<p>
<button @click="addEle">添加元素</button>
<button @click="renderEle">打乱顺序</button>
</p>
<transition-group name="dzx" tag="div" class="list">
<span v-for="item in nums" :key="item">{{item}}</span>
<!-- 不能使用 index index 不稳定 -->
<!-- <span v-for="(item,index) in nums" :key="index">{{item}}</span> -->
</transition-group>
</div>
<script src="./dist/19.js"></script>
</body>
</html>
01 列表过渡.js
import Vue from 'vue';
import './listGuodu.scss';
let app = new Vue({
el: "#app",
data: {
nums: [1, 2, 3, 5]
},
methods: {
// 添加元素
addEle() {
// 随机位置
this.nums.splice(
// 随机一个位置
Math.floor(Math.random() * this.nums.length),
0,
this.nums.length
)
},
// 打乱顺序
renderEle() {
this.nums.sort(() => Math.random() < 0.5 ? 1 : -1)
}
}
})
listGuodu.scss
.list{
span{
font-size: 30px;
font-weight: bold;
padding: 10px;
display: inline-block;
transition: all 1s;
}
}
效果图
② 列表过渡复杂
02.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- <div class="list"> -->
<button @click="render">打乱顺序</button>
<hr>
<transition-group tag="div" name="demo" class="list">
<span v-for="item in arrs" :key="item.index">{{item.value}}</span>
</transition-group>
<!-- </div> -->
</div>
<script src="./dist/22.js"></script>
</body>
</html>
02.js
import Vue from 'vue';
import './guoduLists.scss';
let app = new Vue({
el: "#app",
data: {
arrs: new Array(100).fill(0).map((item, index) => ({ index, value: index % 10 }))
},
methods: {
render() {
this.arrs.sort(() => Math.random() < 0.5 ? 1 : -1)
}
},
})
console.log(app.arrs);
guoduLists.scss
.list{
width: 400px;
height: 420px;
margin: 50px;
border: 1px solid #000;
span{
width: 40px;
line-height: 40px;
text-align: center;
display: inline-block;
box-sizing: border-box;
border: 1px solid #e3e3e3;
// 实现过渡
transition: all 1s;
}
}
效果图
(2) 自定义指令
指令是对DOM元素的拓展,使其具有一定的行为特征(功能)
我们已经学习的指令:
v-bind, v-text, v-html, v-once, v-model, v-cloak, v-on, v-show, v-if, v-else-if, v-else, v-for等等
内置的指令是有限的,有时候我们需要对元素拓展更多的功能,我们要自定义指令
自定义指令只需要两步
第一步,在模板中使用:指令都是以v-为前缀,字母小写,横线分割单词
第二步,在js中定义指令。有两种定义方式
第一种:全局定义:Vue.directive(name, fn | {})
全局定义的指令可以在所有vue实例化对象(组件)中使用
directive方法不能解构,要在vue实例化对象之前定义。
第二种:局部定义:directives: { name: fn | {} }
局部定义的指令只能在当前vue实例化对象(组件)中使用
name表示指令的名称:省略v-前置,使用驼峰式命名
{}表示指令对象,可以定义一些方法
bind :将指令绑定给元素时候执行的方法;
update:指令的属性值发生改变的时候执行的方法
unbind:指令从元素上解除绑定时候执行的方法;
inserted:指令所在的元素从页面中删除时候,执行的方法;
componentUpdated:指令所在的组件更新的时候执行的方法。
fn表示指令函数,处理方法。
不论是指令对象中的方法,还是指令函数,都有四个参数
第一个参数表示指令所在的元素。
第二个参数 表示指令对象,包含指令的一些信息
例如:指令名称,属性值表达式,当前的属性值,上一个属性值等等
第三个参数表示当前的虚拟DOM对象。
第四个参数表示上一个虚拟DOM对象
注意:当多次使用指令的时候,一个指令的属性值改变,所有指令相关的回调函数都会执行。
为了提高性能,我们可以在回调函数中判断当前的值与上一个值是否相同,不同再执行。
请实现以下指令
v-dzx-html => v-html
v-dzx-once => v-once
v-dzx-show => v-show
注:工作中,我们自定义的指令通常带有命名空间前缀
01 实现自定义指令.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 在自定义指令中实现 v-html v-once v-show 指令-->
<!-- 实现 v-html 实现多次可以定义在全局 -->
<div>
<p><input type="text" v-model="msg"></p>
<p v-html="msg"></p>
<!-- 实现自定义指令渲染 -->
<h5 v-dzx-html="msg"></h5>
<hr>
<!-- 实现 v-once 只执行一次 定义在局部即可不用定义在全局 -->
<h5 v-dzx-once="msg"></h5>
</div>
<hr>
<!-- 注意 如果使用 v-html 自定义指令实现两次 操作上面的下面的也会执行 会执行两次 非常消耗性能 -->
<!-- 此问题的解决方法 在 js 文件中 if 判断已解决 -->
<div>
<p><input type="text" v-model="title"></p>
<p v-html="title"></p>
<!-- 实现自定义指令渲染 -->
<h5 v-dzx-html="title"></h5>
</div>
<!-- 实现 v-show 指令 -->
<hr>
<div>
<!-- 属性值是 js 环境 可以直接写 语句 -->
<button @click="isShow=!isShow">切换显隐</button>
<p v-show="isShow">显示 和 隐藏的元素</p>
<!-- 实现 v-show 的自定义指令 -->
<p v-dzx-show="isShow">自定义 show</p>
</div>
</div>
<script src="./dist/20.js"></script>
</body>
</html>
02 实现自定义指令.js
import Vue from 'vue';
// 在全局中定义自定义指令
// Vue.directive('dzxHtml',{
// // 绑定数据
// bind(){
// console.log('bind',this,arguments,"111111");
// },
// // 属性值更新
// update(){
// console.log("update",this,arguments,"222222");
// },
// // 解除绑定
// unbind(){
// console.log("unbind",this,arguments,'33333');
// }
// })
// 在全局中定义自定义指令对上面的操作简化
Vue.directive('dzxHtml',(dom,obj,...args) => {
// console.log(args);
// 判断当前的值与上一个值是否不同
if(obj.value !== obj.oldValue){
// console.log(dom,obj);
// 将数据渲染到页面中
dom.innerHTML = obj.value
}
})
let app = new Vue({
el:"#app",
data:{
msg:'<span>内容显示</span>',
title:"第二个",
isShow:true,
},
// 定义局部指令
directives:{
// 自定义 dzx-once 指令
dzxOnce:{
// 绑定的时候执行
bind(dom,obj){
// console.log(arguments,"111 once");
dom.innerHTML = obj.value
}
},
// 自定义 v-dzx-show 指令
dzxShow(dom,obj){
// console.log(arguments,"2222 show");
// console.log(dom,'dom');
// console.log(obj,'obj');
// 优化
if(obj.value !== obj.oldValue){
// 判断值
if(obj.value){
dom.style.display = ''
} else{
dom.style.direction = 'none'
}
}
}
}
})
// 指令要在 vue 实例之前定义
// Vue.directive('dzxHtml',(dom,obj,...args) => {
// // console.log(args);
// // 判断当前的值与上一个值是否不同
// if(obj.value !== obj.oldValue){
// // console.log(dom,obj);
// // 将数据渲染到页面中
// dom.innerHTML = obj.value
// }
// })
效果图
2.1 自定义指令案例
自定义指令实现表单校验.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<label for="">
用户名
<input type="text" v-model="username">
<!-- 错误提示 -->
<span v-dzx-check="username" test="^\w{4,8}$" error-text="用户名是4-8位的数字字母下划线"></span>
</label>
<hr>
<label for="">
密码
<input type="text" v-model="passworld">
<!-- 错误提示 -->
<span v-dzx-check="passworld" test="^\w{2,6}$" error-text="密码是2到6位的数字字母下划线"></span>
</label>
</div>
<script src="./dist/21.js"></script>
</body>
</html>
自定义指令实现表单校验.js
import Vue from 'vue';
let app = new Vue({
el: "#app",
data: {
username: '',
passworld: ''
},
//定义局部的自定义指令
directives: {
dzxCheck: {
// 绑定的时候执行,执行一次
bind(dom) {
dom.style.color = 'red';
},
// 表单校验指令
update(dom, obj) {
// 性能
if (obj.value !== obj.oldValue) {
// 获取正则内容
let str = dom.getAttribute('test');
// 创建正则
let reg = new RegExp(str);
// 检测输入内容
if (reg.test(obj.value)) {
// 合法不需要提示
dom.innerHTML = '';
} else {
// 不合法进行提示
dom.innerHTML = dom.getAttribute("error-text")
}
}
}
}
}
})
效果图