Vue快速上门(2)-模板语法

image.png

VUE家族系列:

01、模板语法

1.1、template模板

<template>是H5新增的模板元素,是一个用于HTML模板内容的包装元素,主要使用其内部的内容。在普通的HTML页面中,模板会出现在Dom树中,但不会渲染,里面的请求、脚本也不会执行。<template>是Vue里主要的模板定义方式,除此以外,常用的定义Vue.template方式:

Vue.template 描述 示例
<template>模板 H5的模板元素,其内容作为模板内容, <template id="tp">
<script>模板 在一个 <script> 元素中定义模板内容,里面的内容都会被当成字符串。通过#id引用 <script type="text/x-template" id="xtp">
字符模板 用HTML字符串直接定义模板内容 template: '<p>{{name}}</p>'
内联模板inline-template 用在子组件上,用这个子组件元素里面的内容作为模板,而不是渲染他的原本的内容。这个一般不常用吧,作用域有点乱。 <mycom inline-template> </mycom>

📢Vue的template选项值

  • HTML语法:模板内容就是普通的HTML语法,Vue新增了一些绑定数据的指令。
  • 根元素:内部都必须有一个根元素<template>本身是没啥用的,主要用的是其内部InnerHTML。
  • #值:如果值以 # 开始,则它将被用作id选择符,并使用匹配元素的 innerHTML 作为模板。
  • 优先于el:根据上文中Vue生命周期流程可知,template内容会优先于el.outerHTML内容,编译为渲染render。
<div id="app5">
    <h2>app</h2>
    <template>
        <p>vue中的template的innerHtml会被正常渲染</p>
    </template>
    <user-com inline-template>
        <p>内联模板,替代原有内容</p>
    </user-com>
</div>
<script>
    let app5 = new Vue({
        el: "#app5", 
        template: '#tp',  //<template id="tp">模板
        template: '#xtp',  //<script type="text/x-template" id="xtp">模板
        template: '<p>{{mes}}--字符模板</p>', //字符模板
        template: '<p>{{mes}}</p><span>❌</span>', //❌报错:Component template should contain exactly one root element
        data: { mes: "message:hello!" },
        components: {
            'user-com': {
                data: function () { return { name: "same" } },
                template: '<p>{{name}}-这是一个子组件</p>',
            }
        }
    })
</script>

1.2、文本插值

Vue的模板语法基于HTML的语法,可以在模板中申明式的绑定实例数据、事件方法。在Vue中,模板被编译成虚拟Dom渲染函数,先在虚拟Dom上进行操作,这样可以最优化Dom及操作次数,然后再渲染到正式的Dom中。常用的一种数据绑定方式为—— 文本插值

💠文本插值{{ data }},“Mustache”语法 (双大括号) (/ˈmʌstæʃ; məˈstɑːʃ/ 胡子),内容不支持html标签、不支持绑定。

📢注意:安全第一,不要用输入的内容来插值,容易导致XSS攻击。

<div id="app3">
    <div>div1:{{html}}
        <p>{{mes}}</p>
        <p>{{birthday}}</p>
    </div>
    <div v-text="html">div2:</div>
    <div v-html="html">div3:</div>
</div>
<script>
    let vm2 = new Vue({
        el: "#app3",
        data: {
            html: "<span style='color:red'>red span{{mes}}</span>",
            mes: "hello world!",
            birthday: '2000-12-11',
        },
    });
</script>

image.png

1.3、JavaScript表达式

{{文本插值}}v-bind绑定、v-on事件绑定等指令中都支持完全的JavaScript的表达式,只能是单个表达式语句,不支持复杂语句、循环控制。

<div id="app3">
    <div>
        <p v-bind:style="'color:'+fcolor">{{mes.split(' ').join('---')}}</p>
        <p>age:{{(new Date().getFullYear() - new Date(birthday).getFullYear())}}</p>
        <p>age:{{((new Date() - new Date(birthday))/3600/24/365/1000).toFixed(1)}}</p>
    </div>
</div>
<script>
    let vm2 = new Vue({
        el: "#app3",
        data: {
            mes:"hello world!",
            birthday:'2000-12-11',
            fcolor:'red',
        },
    });
</script>

image.png


02、模板指令

2.1、指令大全🔖

指令格式:指令:参数.修饰符 = "值"

Vue指令/ 简写 描述 示例
v-text= 绑定 textContent,同{{文本插值}}(如JS延迟,有闪烁) <span v-text="msg"></> = <span>{{msg}}</>
v-html= 绑定 innerHTML,内容支持html标签(不支持绑定),需注意安全性。其他插值指令的值都不支持HTML标签,会被转义。 <div v-html="html"></div>
v-bind: = / := 绑定元素属性值,动态地绑定一个或多个 attribute,或组件prop <img v-bind:src="img" :class="imgStyle">
v-model= 表单元素的值双向绑定,不支持表达式 <input type="date" v-model="birthday">
v-show= 值为真元素显示(切换 display),适用于频繁切换显示。 <div v-show="value =='方案1'">方案1</div>
v-if= 值为真才渲染,否则不会创建或销毁已有元素,支持<template> <img v-if="growth > 0" alt="上升">
v-else-if= v-if else if块,可连续使用,跟在v-if/v-else-if后面 <img v-else-if="growth < 0" alt="下降">
v-else v-if 或者 v-else-if 添加的“else 块”,无参数 <img v-else alt="稳定">
v-for= 列表渲染item in/of expression,支持index索引、对象 <li v-for="item in items">{{item}}</li>
v-on: = / @= 绑定事件,参数为事件名;值为方法名,或内联语句func($event) <button v-on:click="submit" @click="">
:key= 元素唯一key值,配合v-for使用,避免重复key更新异常,用于虚拟Dom中判断新旧元素。或用于强制元素替换而不复用 ul v-for="item in list" :key="item.id">
<i:key="text">{{text}}</i> //每次都是新元素
v-once 只更新元素/组件一次,后续更新都视为静态内容,不再更新 <p v-text="message" v-once></p>
v-pre 不编译,跳过这个元素和它的子元素的编译过程,显示原生的内容 <div v-pre> </div>
is 动态的绑定一个组件,值为组件名称/Vue选项对象 <component is="user-info"></component>
v-slot:= / #:= 具名插槽,有名分的插槽。指定插槽名称,或绑定插槽ViewModel v-slot:header v-solt="{user}"
ref 给子组件、Dom元素注册引用名,通过$refs访问这些被ref标记的对象 组件上的ref指向其组件Vue实例
<div ref="left">
v-cloak 解决{{文本插值}}会闪烁的问题,锁定[v-cloak]样式直到编译完后清除 [v-cloak]{ display: none;} <div v-cloak>

2.2、[动态参数]

2.6.0新增的[动态参数],指令的参数可以使用[动态参数]=一个JavaScript表达式。

<a v-on:[functype]="setStyle" v-bind:[href]="1+1">方案1</a>

  • 字符串值:这里的动态参数预期结果为一个字符串,异常则为nullnull也可用于显示的移除绑定。
  • 不要出现引号,包括空格、引号、<>/=,HTML的属性中是非法的。
  • 参数名用小写,不要用大写,浏览器会强制转换HTML属性为小写。如<a v-on:[funcType]="fswitch">方案1</a> 包含大写的属性参数会找不到对应值。
<div id="app">
    <img v-bind:[getProp(file.type)]="file.url" alt="file" v-on:[eventType]="eventHandler">
    <img v-bind:[getprop1]="file.url" alt="file" v-on:[eventType]="eventHandler">
</div>
<script>
    let vm2 = new Vue({
        el: "#app",
        data: {
            file: { type: 'img', url: '../../res/bg.gif' },
            eventType: 'click', //大写会找不到,报错:Property or method "eventtype" is not defined
            eventtype: 'click',
        },
        computed:{ getprop1(){ return 'src'; } },
        methods: {
            getprop(type) {   //如果有大写(getProp)就会找不到报错:Property or method "getprop" is not defined
                switch (type) {
                    case 'img': return 'src';
                    case 'url': return 'href';
                }
            },
            eventHandler(e) { console.log(e.target.tagName); }
        }
    });
</script>

2.3、v-for 列表渲染

用循环创建多个元素/组件,循环对象可以是数组、对象、常量,也可以是计算属性方法表达式。循环表达式中可以用in,也可用of(没有区别)。如果循环创建多个元素没有根元素,则可用一个模板<template>来包裹,这时就不需要key了。

  • 列表循环v-for="item in items"
  • 列表循环-带索引参数v-for="(item,index) in items"
  • 对象循环-valuev-for="value in user",Vue是按照Object.keys(obj) 的结果遍历。
  • 对象循环-带参数v-for="(value,name,index) in user"
<div id="app">
    <span v-for="n of 20">{{ n }} </span>
    <ul>
        <li><span v-for="item in items">{{item.name}} ; </span></li>
        <li><span v-for="(item,index) in items">{{index+1}}:{{item.name}} ; </span></li>
        <!--user对象-->
        <li><span v-for="value in user">{{value}} ; </span></li>
        <li><span v-for="(value,name,index) in user"><i>{{index+1}}</i>)<b>{{name}}</b>:{{value}} ; </span></li>
    </ul>
    <br>
</div>
<script>
    let vm2 = new Vue({
        el: "#app",
        data: {
            items: [{ name: 'sam' }, { name: 'zhangsan' }],
            user: { name: 'sam', age: 20, birthday: '2000-12-11' }
        },
    });
</script>

image.png

🔸列表更新策略(:key):Vue默认列表项原地更新,不管数据的顺序。

如果希望更新时保持数据、元素的顺序,及更新的准确性、高性能,则需要给元素设置一个唯一身份标识 key:v-bind:key="kid" :key="kid",值应为字符、数字

Vue默认是最大限度复用元素,虚拟Dom中用key来判断新旧元素,重复key可能会导致更新异常,也可用于强制元素替换而不复用。一般推荐尽量提供key,他是Vue识别节点的通用机制(diff中的元素比较)。在<transition-group>列表动画中,key是必须的。

📢 注意

  • v-for循环中的参数的顺序须一致,别名不重要。
  • v-for优先级高于v-if,共用时需注意,可用来过滤不符合条件的项。

2.4、class样式绑定

classstyle为HTML原本的attribute,通过v-bind绑定,增强:

  • 对象绑定,语法:{classA:bindbool, classB:bindbool},绑定值bindbool为真则样式classA有效,方便基于判断绑定多个class。除了直接对象表达式,还可以是绑定的对象、计算属性返回的对象、普通表达式。
  • 数组绑定,绑定多个样式,数组中可以是绑定值、表达式、常量样式名。
  • 支持和原生class共存,会合并class值。包括组件也是如此,和组件的根元素class合并。

🌰一个tab切换示例:

<style>
    #app5 ul { list-style-type: none; margin: 0; padding: 0; text-align: center; }
    #app5 ul li { display: inline-block; margin: 0 10px; }
    #app5 ul li.active { background-color: antiquewhite; }
    .psection {
        display: none; background-color: antiquewhite;
        text-align: center; margin: 0; line-height: 50px;
    }
    .psection.active { display: block; }
</style>
<div id="app5">
    <ul>
        <li v-for="item in items" v-on:click="liclick(item)" v-bind:class="{active:item.isActive}">{{item.title}}</li>
    </ul>
    <div>
        <p v-for="item in items" v-bind:class="['psection',item.isActive?'active':'']">{{item.content}}</p>
        <!-- 也可以用v-show实现切换 v-show="item.isActive" -->
        <p v-for="item in items" v-show="item.isActive">{{item.content}}</p>
    </div>
</div>
<script>
    let app5 = new Vue({
        el: "#app5",
        data: {
            items: [{ title: "显示1", content: "1", isActive: false }
                    , { title: "显示2", content: "2", isActive: true }
                    , { title: "显示3", content: "3", isActive: false }],
        },
        methods: {
            liclick: function (item) {
                this.items.forEach(item => item.isActive = false);
                item.isActive = true;
            },
        }
    })
</script>

image.png

2.5、style内联样式绑定

对于Style的绑定,Vue直接把style对象化了,通过对象化表达式,或者直接一个对象绑定(更清晰)。

  • 对象数组:支持多个对象的数组,合并对象中的style样式规则。
  • 支持一定的兼容性前缀,如transition,Vue会自动检测浏览器并添加兼容性前缀。
  • 对象属性多重值,提供多个值的数组display:['-ms-flexbox','flex'],Vue只会渲染数组中最后一个被浏览器支持的值。
<div id="app5">
    <div>
        <!--数组+对象混合-->
        <p :style="[{color:activeColor,'font-size':'20px'},marginStyle]"> p1 - Content </p>
        <p v-bind:style="marginStyle"> p2 - Content </p>  <!--对象-->
    </div>
</div>
<script>
    let app5 = new Vue({
        el: "#app5",
        data: {
            activeColor: 'red',
            marginStyle: { margin: "30px", transform: "rotate(10deg)", display: ['-ms-flexbox', 'flex'] },
        },
    })
</script>

2.6、v-on/@事件.修饰符

事件绑定格式:v-on:/@ 事件名.修饰符 = ""@v-on:的缩写形式。事件名支持动态 [参数] 绑定。Vue的事件都是直接绑定到元素的,没有用事件委托。

事件参数:方法默认支持事件参数对象Event,内联JavaScript代码通过$event访问事件对象。

<div id="app7">
    <!-- 只响应一次 + 右键点击 -->
    <button @click.once.right="arrClick">button</button>
    <li v-for="n in arr"><button v-on:click="arrClick($event,n)">{{n}}</button></li>
    <!-- 左方向按键,数值增1 -->
    <input type="text" v-on:keydown.preven.arrow-left="num=parseInt(num)+1" v-model="num">
</div>
<script>
    let app7 = new Vue({
        el: "#app7",
        data: { arr: [1, 2, 3], num: 0 },
        methods: {
            arrClick: function (e, arg) { console.log(e?.target.tagName, arg ? arg : "") },
        }
    })
</script>

🔸修饰符 可以加强事件的能力,使用上可以串联(注意顺序),也可以只有修饰符。

修饰符 描述
.stop 调用 event.stopPropagation()停止向上冒泡(propagation /ˌprɒpəˈɡeɪʃn/ 传播)
.preven 调用 event.preventDefault()取消默认事件行为,如checkbox、<a>的默认事件行为,不影响冒泡
.self 只当事件是从侦听器绑定的元素本身触发时才触发回调,只能自身触发,内部冒泡事件的不会响应。
.once 只触发一次回调
.capture 添加事件侦听器时使用 capture(捕获)模式,事件流的捕获阶段就触发事件。
.passive (2.3.0) 以 { passive: true } 模式添加侦听器,passive 设为 true 可以启用性能优化,主要是针对滚动、触摸相关事件。参考MDN:使用 passive 改善滚屏性能,(passive /ˈpæsɪv/被动,消极)。
.native 监听组件根元素的原生事件
鼠标键修饰符 .left:只当点击鼠标左键时触发。.right:鼠标右键触发;.middle:鼠标中键触发
辅助键修饰符 配合鼠标、按键事件使用:ctrl、shift、alt、meta(windows键,或command)
键盘事件修饰符 针对事件keydownkeyupkeypress按键修饰符:
● esc、tab、space、enter、delete、up、down、left、right、a、b、c字母键等。
.{keyCode &#124; keyAlias}按键修饰符,只当事件是从特定键触发时才触发回调。可使用 KeyboardEvent.key值转换为 kebab-case 来格式使用。

2.7、v-model表单绑定

使用v-model在表单元素<input><textarea><select>上创建双向绑定,会忽略他们本身的值属性(value、checked、selected),所以注意设置默认值。分组的单选、多选元素组按照name进行分组即可,一组的绑定也是一样的。

基本原理就是监听表单的输入事件,实现视图到数据的同步:

  • texttextarea 元素使用 value propertyinput事件。
  • checkboxradio 使用 checked propertychange 事件。name用于分组命名空间,value作为选中的值。
  • select 字段将 value 作为 prop 并将 change 作为事件。

🔸v-model 修饰符

  • .lazychange 事件同步数据,主要针对text类表单元素,失去焦点时才会触发change事件。
  • .number:强制转换值为数值类型,需配合type="number"使用,如果无法 parseFloat() 解析则返回原始值。
  • .trim:去掉首尾空格,比较实用!
<div id="app8">
    <div>
        <label>姓名:<input type="text" v-model.lazy.trim="name"></label>
        <label>姓名:<input type="number" v-model.number="age">{{age}}</label>
    </div>
    <div>
        <span>性别:</span>
        <template v-for="(value,name) in dataset.sex">
            <label><input type="radio" v-model.lazy="sex" name="sex" :value="name">{{value}}</label>
        </template>
        <i>结果:{{sex}}</i>
    </div>
    <div>
        <span>技能:</span>
        <label v-for="item in dataset.skill"><input type="checkbox" v-model="skill" :value="item"
                                                 name="skill">{{item}}</label>
        <i>结果:{{skill}}</i>
    </div>
    <div>
        <span>性别-选择框:</span>
        <select name="ssex" v-model="sex">
            <option disabled value="">请选择</option>
            <option v-for="(value,name) of dataset.sex" v-once :value="name">{{value}}</option>
        </select>
        <i>结果:{{sex}}</i>
    </div>
    <div>
        <span>技能-选择框:</span>
        <select name="sskill" v-model="skill" multiple>
            <option disabled value="">请选择</option>
            <option v-for="item in dataset.skill" v-once :value="item">{{item}}</option>
        </select>
        <i>结果:{{skill.join()}}</i>
    </div>
</div>
<script>
    let app8 = new Vue({
        el: "#app8",
        data: {
            name: '', age: 0, checked: false, sex: '', skill: ["开机"],
            dataset: {
                sex: { male: '男', female: "女", other: '其他' },
                skill: ['开机', '关机', '写Bug', '吃饭'],
            }}
    })
</script>

image.png

2.8、关于数据丢失

基于Vue对数据监听的机制,Vue 不能检测数组和对象的变化。因此有些场景数据无法实现变更监听,就无法同步视图了,造成“数据丢失”的现象。

  • 数组通过索引修改、新增的值无法监听。
  • 未初始化的新成员,添加的对象新成员,没有被初始化时监听,app1.user.新属性=20
  • 被冻结的对象无法监听:Object.freeze(obj)
  • v-model 绑定的未定义属性不丢失!因为他是用的$set去更新的,注意不能是data的一级属性。

image.png

🟢解决办法

  • 数组整体赋值:新数组赋值,或者用数组方法修改数据,如push方法是被Vue代理实现了拦截的。

  • 在Vue初始化时先申明属性。

  • vm.$set.(obj)强制更新,会先添加响应,然后再更新视图。不建议动态添加data的一级属性!在选项中预先申明。好像是一些边界方面的技术原因。

<div id="app">
    <p>p1:
        <span v-for="n in arr">{{n}},</span>
    </p>
    <p>p2:
        <b>name:</b>{{user.name}},
        <b>age:</b>{{user.age}}
    </p>
</div>
<script>
    let app = new Vue({
        el: '#app',
        data: { arr: [1, 2, 3], user: { name: 'sam' }, }
    })
    app.arr[0] = 100;  //修改,无更新
    app.arr[app.arr.length] = 4; //新增,无更新

    app.$set(app.arr,0,101); //强制更新
    app.arr.push(5); //push有效,前面的也生效了,因为触发了更新
    app.arr = [100, 2, 3];  //重新赋值数组,有效
    app.arr = Array.of(...Array.from(app.arr),10,10); //重新赋值数组,有效

    app.user.age = 10; //这是新的属性,无更新
    app.$set(app.user,'age',18); //强制更新,有效
    app.user = Object.assign({}, app.user);
    app.user = user; //赋值对象,有效
</script>

03、Vue动画

Vue提供了两个内置元素,<transition><transition-group>,用来包装单个元素、列表元素,辅助实现在元素显示隐藏、创建删除、移动过程中的过渡动画效果。更高级、更复杂的动画可以借助第三方动画组件来实现。

3.1、transition过渡动画

Vue提供了一个<transition>封装组件,用来包装需要动画的单个内容。Vue主要提供了一个比较基础的动画机制,帮你处理过渡的事件、动画类调用。所以还是需要你自己来写动画的CSS类,或者动画JS代码。

image

  • 三种类型的过渡:元素初始渲染过渡、元素进入过渡(显示)、元素离开过渡(隐藏/删除)。
  • 包裹单元素<transition>只能包裹一个跟元素(包括v-if、v-show切换),动画应用在这个跟元素上,不会产生额外Dom元素。
  • 过河拆桥--事后清理:动画完成后,CSS动画资源会被清除,Vue会自动监听transitionend,或animationend事件。
  • 过渡CSS类名规范:如下表格,按照CSS类名写样式,Vue自动调用。v为动画组件<transition>name值,没有则默认v
  • CSS过渡类attribute:作用同上,值是Class样式类名,优先级更高。CSS值可以自定义,也可以很方便的调用第三方CSS动画库。
进入过渡 离开过渡 CSS过渡类attribute,优先级更高
v-enter:初始点状态 v-leave:初始点状态 enter-class、leave-class
v-enter-to:结束点状态 v-leave-to:结束点状态 enter-to-class、leave-to-class
v-enter-active:进入过程,设置动画参数 v-leave-active:离开过程 enter-active-class、leave-active-class

🌰过渡动画示例:CodePen

<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet">
<div id="app15">
    <div>
        <button v-on:click="acitve = !acitve" ref="btn">消失</button>
        <transition name="h" v-on:after-enter="updateBtn" v-on:after-leave="updateBtn">
            <p v-show="acitve" style="color:red">秦时明月汉时关,万里长征人未还!</p>
        </transition>
        <!-- CSS过渡类Class,使用了animate组件-->
        <transition name="h" enter-active-class="animated fadeInRightBig" leave-active-class="animated zoomOut">
            <p v-show="acitve" style="color:blue">秦时明月汉时关,赶快下楼做核酸!</p>
        </transition>
    </div>
</div>
<style>
    .h-enter-active,
    .h-leave-active { transition: all 0.5s cubic-bezier(1.0, 0.8, 0.5, 1.1); }
    .h-enter, .h-leave-to { opacity: 0; }
    .h-enter { transform: translateX(80px); }
    .h-leave-to { transform: translateX(-80px); }
</style>
<script>
    let app15 = new Vue({
        el: "#app15",
        data: { acitve: true },
        methods: {
            updateBtn: function (e) { this.$refs.btn.innerText = this.acitve ? "消失" : "出来"; }
        }
    })
</script>

1.gif

transition动画元素的属性、钩子事件:

✔️<transition>属性 描述
name 用于自动生成 CSS 过渡类名:name-entername-leave
appear 开场动画,是否在初始渲染时使用过渡,bool,默认为 false
css bool,是否使用 CSS 过渡类,默认ture。如果用钩子函数JS控制动画,可以关闭css。
type Vue 监听过渡事件类型类型,用于动画完成后清理class资源,animation (animationend) 或 transition(transitionend
mode 过渡模式,控制新旧元素进入/离开过渡的先后顺序, out-inin-out,默认同时进行。
duration 过渡的持续时间(ms),{ enter: 500, leave: 500} ,用于事后清理资源,而不是设置动画时间
✔️CSS 过渡类 attribute
进入过渡 enter-class、enter-to-class、enter-active-class
离开过渡 leave-class、leave-to-class、leave-active-class
初始渲染过渡 appear-class、appear-to-class、appear-active-class
✔️JavaScript 钩子 用于JS的动画控制,可以借助第三方JS动画库
进入过渡 before-enter(el)、enter(el, done)、after-enter(el)、enter-cancelled(el)
当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。
离开过渡 before-leave(el)、leave(el, done)、after-leave(el)、leave-cancelled (el)
leaveCancelled 只用于 v-show 中
初始渲染过渡 before-appear(el)、appear(el)、after-appear(el)、appear-cancelled(el)

3.2、transition-group列表过渡动画

列表的过渡是针对多个元素,需要 transition-group组件,支持的过渡类、特性和事件和<transition>类似,多了tag移动过渡。不过过渡针对的不是一个根元素,而是内部的每一个一级元素。<transition-group>会产生一个元素<span>,可通过tag修改渲染的元素,比如用来代替<ul>不错。

<transition-group> 描述
tag <transition-group>产生的元素标签名,默认为span,可以根据需要设置。
✔️CSS 过渡类 attribute
移动过渡 move-class(类名:v-move)

如果只是用进入、离开过渡,会导致其他元素的位置变化比较生硬。使用移动过渡v-move/move-class,在元素改变定位的时候使用。Vue 使用了一个 FLIP 的动画队列,使用transforms将元素位置平滑移动。

📢v-for 时需设置keyv-for创建列表元素时,强烈建议设置列表项的key值,列表动画中这是强制要求了!

代码示例:CodePen

<h1>app15: 动画</h1>
<div id="app15">
    <h3>列表动画:<button @click="shuffle">随机乱序</button></h3>
    <div>
        <transition-group tag="ul" name="list" enter-active-class="animated flipInX">
            <li v-for="(s,i) in list" v-bind:key="s">{{s}}
                <button @click="list.splice(i,1)">-</button> 
                <button @click="list.splice(i+1,0,s+index++)">+</button>
            </li>
        </transition-group>
    </div>
</div>
<style>
    .list-enter { opacity:0; }
    .list-enter-to{ transform: translateX(50px); }
    .list-leave-active{ transition: all 1s; }        
    .list-leave-to { opacity: 0; transform: translateX(50px); }
    .list-leave-active {
        position: absolute;   /*让元素移动更顺滑*/
        transition: all 1s; }
    .list-move { transition: 0.5s; }
</style>
<script>
    let app15 = new Vue({
        el: "#app15",
        data: { acitve: true, index: 1, list: ['张三', '李四', '王五', '对六', '小七', '李白'] },
        methods: {
            // 随机排序
            shuffle: function () { this.list.sort((a, b) => Math.random() - 0.5) }
        }
    })
</script>

1.gif


©️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀

posted @ 2022-12-12 09:56  安木夕  阅读(552)  评论(1编辑  收藏  举报