Vue 学习 第二篇 transition + transition-group +自定义指令

一、 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")
                    }
                }
            }
        }
    }
})

效果图
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大闸蟹~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值