vue 基础(五)

动画过渡与表单的数据绑定

动画过渡

单一元素/组件的过渡

概念:Vue 在元素显示隐藏时, 提供了 transition 的封装组件,可以给任何元素和组件添加进入/离开过渡

语法<transition name="过渡css名">单一标签</transition>

被transition标签包裹的元素在其显示隐藏时,六个不同的阶段会自动添加6个class名:

元素进入的第一帧 [transition name 属性]-enter

元素进入中 [transition name 属性]-enter-active

元素进入的最后一帧 [transition name 属性]-enter-to

元素离开的第一帧 [transition name 属性]-leave

元素离开中 [transition name 属性]-leave-active

元素离开的最后一帧 [transition name 属性]-leave-to

<div id="app">
        <!--
        被transition标签包裹的元素在其显示隐藏时,六个不同的阶段会自动添加6个class名
        元素进入的第一帧  [transition name 属性]-enter
        元素进入中        [transition name 属性]-enter-active
        元素进入的最后一帧 [transition name 属性]-enter-to
        元素离开的第一帧   [transition name 属性]-leave
        元素离开中        [transition name 属性]-leave-active
        元素离开的最后一帧 [transition name 属性]-leave-to
        -->
    <transition name="fade">
      <div class="box" v-if="show"></div>
    </transition>

    <button @click="show = !show">show/hidden</button>

</div>

<script>
 let vm = new Vue({
            el: '#app',
            data: {
                show: true
            }
        })
</script>
    
<style>
        .box {
            width: 100px;
            height: 100px;
            background-color: green;
        }

        .fade-enter,  .fade-leave-to{
            /*元素进入动画第一帧 类名*/
            opacity: 0;
            transform: translateX(300px);
            width: 0;
            height: 0;
        }

        .fade-enter-active, .fade-leave-active {
            /*元素进入整个过程中 类名*/
            transition: all .5s linear;
        }

        .fade-enter-to, .fade-leave {
            /*元素进入动画最后一帧 类名*/
            opacity: 1;
            transform: translateX(0);
            width: 100px;
            height: 100px;
        }
</style>

注意:

  1. transition 标签内只能包含一个直接子元素
  2. transition 标签的name属性可以省略, 省略后元素进入离开时类名默认使用v-开头,例: v-enter v-enter-to v-leave v-leave-to。

列表的进入/离开过渡

概念: 因为transition标签内部只能监听单个节点,或同一时间渲染多个节点中的一个。所以transition标签内部无法监听多个节点的。所以vue提供了 <transition-group> 组件实现内部监听多个节点的进入离开

语法: <transition-group name="过渡css名">多个标签</transition-group>

<div id="app">
    <transition-group name="fade">
              <p v-for="c in arr" :key="c">{{c}}</p>
    </transition-group>
</div>

<script>
        let vm = new Vue({
            el: '#app',
            data: {
                arr: ['a', 'b', 'c', 'd', 'e']
            }
        })
</script>

<style>
        .fade-enter, 
        .fade-leave-to {
            transform: translateX(100px);
        }

        .fade-enter-active, 
        .fade-leave-active {
            transition: all .5s linear;
        }

        .fade-enter-to, 
        .fade-leave {
            transform: translateX(0);
        }
</style>

注意

  • 在transition-group组价中,列表渲染的key不能使用index。index作为key在添加或者删除时会导致不是正确的DOM节点被移除
<!--
请观察下面代码,
我们在使用 transition-group 元素时内部兄弟节点使用数组每一项的值作为key ':key="c"' (因为key值必须唯一所以请不要让数组中包含相同的值),
这时请尝试添加或删除数组中的某一项,你胡发现动画效果是正确的
但是如果我们使用数组下标作为key后,元素的添加或删除动画会异常
-->
<div id="app">
    <transition-group name="fade">
        <p v-for="(c,i) in arr" :key="i">
            {{c}}
            <button @click="removeArr(c)">remove</button>
        </p>
     </transition-group>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            arr: ['a', 'b', 'c', 'd', 'e']
        },
        methods: {
            removeArr(c) {
                this.arr = this.arr.filter(a => a !== c)
            }
        }
    })
</script>

<style>
    .fade-enter,
    .fade-leave-to {
        transform: translateX(100px);
    }

    .fade-enter-active,
    .fade-leave-active {
        transition: all .5s linear;
    }

    .fade-enter-to,
    .fade-leave {
        transform: translateX(0);
    }
</style>
  • transition-group会被vue默认渲染成一个span元素,如果你想设置transition-group组件渲染输出的节点可以设置其tag属性,例 tag="ul" transition-group组件就会被渲染成ul标签
<transition-group tag="ul" name="move">
                <li v-for="todo in todos" :key="todo.id">
                   {{todo.text}}
                </li>
</transition-group>

JavaScript 动画钩子

概念:无论transition 和 transition-group 标签都支持使用动画js钩子。动画的钩子就是元素在整个动画过渡中默写特殊的时间点。当动画到达这些时间点时就会触发js钩子所绑定方法。有了js动画钩子就可以实现一些复杂的动画。

语法:动画钩子就是vue提供的一些自定义事件,监听响应的事件触发绑定的函数

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>

<transition-group
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition-group>

注意:动画钩子事件会将当前动画元素作为参数传入到函数内部

<!--
Velocity 和 jQuery.animate 的工作方式类似,也是用来实现 JavaScript 动画的一个很棒的选择
-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>    
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <div id="app">
        <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
            <div v-show="show" class="box"></div>
        </transition>

        <button @click="show = !show">show/hidden</button>
    </div>

    <script>
        console.log(Velocity)
        new Vue({
            el: "#app",
            data: {
                show: true
            },
            methods: {
                beforeEnter(el) {
                    console.log(el, '元素将要显示')
                    el.style.opacity = 0
                },
                enter(el, done) {
                    console.log('元素正在显示')
                    Velocity(el, {
                        opacity: "1",
                        translateY: '30px',
                    }, {
                        duration: 400,
                        easing: "swing",
                        loop: 2,
                        complete: done // 动画结束后触发done表示自定义动画结束
                    });
                },
                afterEnter(el) {
                    el.style.opacity = 1
                    // console.log(el.offsetHeight)
                    console.log('元素显示完毕')
                }
            }
        })
    </script>

注意:动画钩子事件会中enter事件与leave事件除了会默认传递第一个参数el(当前动画元素)以外,还会传递第二个参数 done,done 是一个方法用来告诉Vue当前元素的自定义动画已经结束,动画钩子才会执行下一步 after-enter 或者after-leave。如果自定义动画效果结束后不调用done可能会导致动画元素样式不更新

表单的数据绑定

概念: 在开发中我们经常需要创建一些表单元素,表单元素的内容由vue实例中的data控制。而用户在表单上的输入操作又可以修改实例中的数据。上面的行为我们称之为表单的双向绑定。

例子: 下面的代码就是实现input表单的双向绑定

<div id="app">
   <input v-bind:value="str" @input="inputHandel">
   {{str}}
</div>

<script>
new Vue({
     el: "#app",
     data: {
         str: 'hello world'
     },
     methods: {
         inputHandel(evt) {
            this.str = evt.target.value 
         }
     }
})
</script>

注意

  • Vue为了简化表单元素的数据绑定, input 、select、 textarea 这些值绑定全部统一使用value属性,但是单复选框依然是checked属性
<div id=app>    
    <input v-bind:value="str" @input="inputHandel">
    {{str}}
    <textarea :value="str"></textarea>
    <select :value="city">
        <option value="bj">北京</option>
        <option value="sh">上海</option>
        <option value="gz">广州</option>
        <option value="sz">深圳</option>
    </select>
    
    <input type="checkbox" :checked="true">
</div>

<script>
        new Vue({
            el: "#app",
            data: {
                str: 'hello world',
                city: 'sz'
            },
            methods: {
                inputHandel(evt) {
                    this.str = evt.target.value 
                }
            }
        })
</script>
  • 虽然Vue帮我们简化了表单元素值得绑定,但是在不同表单元素之间依然有一些差异的。要根据不同的表单元素差异绑定不同的属性与方法还是有些繁琐。这时Vue为了帮我们解决表单的差异,提供了一个v-model的指令v-model本质上是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

语法v-model="data属性"

<div id="app">
   <input v-model="str">
   {{str}}
   <textarea v-model="str"></textarea>
   <p>{{city}}</p>
   <select v-model="city">
               <option value="bj">北京</option>
               <option value="sh">上海</option>
               <option value="gz">广州</option>
       <option value="sz">深圳</option>
   </select>
   <p>{{agree? '同意' : '不同意'}}</p>
   <input type="checkbox" v-model="agree">
</div>

<script>
new Vue({
     el: "#app",
     data: {
       str: 'hello world',
       city: 'sz',
       agree: false
     }
})
</script>

注意: v-model 绑定支持表单元素的复选时,v-model绑定的数据请使用数组类型

<div id="app">
    <!-- 选择器当设置了可复选属性时,会自动将v-model中的数据转化为数组 -->
    <select v-model="city" multiple>
    <option value="" disabled>请选择你所在的城市</option>
    <option value="bj">北京</option>
    <option value="sh">上海</option>
    <option value="gz">广州</option>
    <option value="sz">深圳</option>
    </select>
 
  <!--复选框要实现复选时,必须将v-model中的数据设置为数组-->
  <p>爱好{{hobbys}}</p> 
  <label>
    抽烟
    <input type="checkbox" value="抽烟" v-model="hobbys">
  </label>
  <label>
    喝酒
    <input type="checkbox" value="喝酒" v-model="hobbys">
  </label>
  <label>
    烫头
    <input type="checkbox" value="烫头" v-model="hobbys">
  </label>
  <label>
    玩摇滚
    <input type="checkbox" value="玩摇滚" v-model="hobbys">
  </label>
</div>

<script>
new Vue({
     el: "#app",
     data: {
       city: '',
       hobbys: []
     }
})
</script>

修饰符

.lazy

在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步:

<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">

.number

如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

<!--
    即使表单元素设置的type="number"属性但是表单的value依然是字符串
-->
<input v-model.number="age" type="number">

注意: 这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。

.trim

如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

<input v-model.trim="msg">
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容