VUE内置组件 vue使用插槽分发内容 组件缓存 实现动画的过渡效果

动态组件

除了允许用户自定义组件之外,Vue还内置了一些组件,以帮助用户高效地开发一些功能。本章将带领大家一起来了解这些内置组件。
某些时候需要动态切换页面部分区域的视图,这个时候内置组件component就显得尤为重要。 component接收一个名为is的属性,is的值应为在父组件中注册过的组件的名称,用法如下:
< !-- view为变量 -->

下面来看一个示例,代码如下:

 <style>
   .tabs {
     margin: 0;
     padding: 0;
     list-style: none;
   }
   .per-tab {
     display: inline-block;
     width: 120px;
     line-height: 32px;
     border-left: 1px solid #ccc;
     border-top: 1px solid #ccc;
   }
   .per-tab:last-child {
     border-right: 1px solid #ccc;
   }
   .tab-content {
     height: 240px;
     border: 1px solid #ccc;
    }
 </style>
 <div id="app">
   <ul class="tabs">
     <li class="per-tab" @click="toggleView('Home')">Home</li><!--
     --><li class="per-tab" @click="toggleView('About')">About</li>
   </ul>
   <div class="tab-content">
     <component :is="view"></component> <!-- view为变量 -->
   </div>
 </div>
 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.
 js"></script>
 <script type="text/javascript">
   let Home = {  // Home组件
     template: '<p style="color: #787878;">Hello Home!</p>'
   }
   let About = {  // About组件
     template: '<p>Hello About!</p>'
   }
   let vm = new Vue({  // Vue实例
     el: '#app',
     components: { Home, About },
     data () {
        return {
          view: 'Home'
        }
     },
     methods: {
        toggleView (view) {
          this.view = view
        }
     }
   })
 </script>
 

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

点击两个组件会呈现不同的字
定义了Home和Aboat两个组件,并使用components选项将其注册到实例vm中,初始时设置is的值为Home:

data () {
return {
view: ‘Home’
}
},

使用插槽分发内容

通过props选项,组件可以接收多态的数据,如何接收多态的DOM结构呢? 实现方法有很多,比如使用props配合v-html等。这里,Vue提供了一种更简单的选择,使用内置组件slot(插槽)分发内容。 在定义多个插槽时,我们可以使用name属性对其进行区分,如果没有指定name属性,则Vue会将所有的插槽内容置于默认插槽default中。 下面来看一段示例代码:

  <div id="app">
       <slot-test>
         <p>使用插槽分发内容</p>
         <h1 slot="header">插槽测试!</h1>
         <p>在组件中,没有指定插槽名称的元素将被置于默认插槽中</p>
         <p slot="none">指定到不存在的插槽中的内容将不会被显示</p>
       </slot-test>
     </div>
     <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.     js"></script>
     <script type="text/javascript">
       let SlotTest = {
         template: '<div>' +
          '<slot name="header">相当于占位元素,因此这些文字也不会被渲染</slot>' +  //
     具名插槽
         '<slot></slot>' +  // 默认插槽
         '</div>'
       }
       let vm = new Vue({  // Vue实例
         el: '#app',
         components: { SlotTest }
       })
     </script>

在这里插入图片描述
是通过 < slot name=“header”>相当于占位元素,因此这些文字也不会被渲染’ 和 < h1 slot=“header”>插槽测试!
来进行渲染的,可以看到 < p slot=“none”>指定到不存在的插槽中的内容将不会被显示< /p> 这句话并没有显示出来。说明父组件的元素被成功分发导对应插槽中。
VUE还提供了作用域插槽slot-scope(在VUE2.5以下版本为scope,只可用于template元素)我们可以用slot-scope获取子组件回传的数据,用来在父组件中执行多态的渲染或响应

一个实例:

<body>
<style>
    #app {
        color: #206fbf;
        font-family: Roboto, sans-serif;
    }
    .label {
        display: inline-block;
        min-width: 160px;
    }
</style>
<style>
    .tabs {
        margin: 0;
        padding: 0;
        list-style: none;
    }
    .per-tab {
        display: inline-block;
        width: 120px;
        line-height: 32px;
        border-left: 1px solid #583b3b;
        border-top: 1px solid #e21a1a;
    }
    .per-tab:last-child {
        border-right: 1px solid #7f0303;
    }
    .tab-content {
        height: 240px;
        border: 1px solid #0f7f8d;
    }
</style>
<style>
    .btn {
        outline: none;
        border: none;
        cursor: pointer;
        padding: 5px 12px;
    }
    .btn-text {
        color: #409eff;
        background-color:#42b983;
    }
    /*这个backgroundcolor是改变切换标记的背景颜色*/
    .btn-text:hover {
        color: #ff66b5;}
    /*}这个是改变点击切换标记之后水果显示的颜色*/
    . fly-table {
        width: 400px;
        text-align: left;
        line-height: 42px;
        border: 1px solid #b37f3f;
        user-select: none;
    }
</style>
<div id="app">
    <h2>Fly Table Component</h2>
    <button
            class="btn btn-text"
            title="点击使数组倒序"
            @click="handleReverse">
<!--        /* 用来倒序的函数*/-->
        倒序
    </button>
    <fly-table
            :fields=" fields"
            :goods="goods">
    <!-- 组件标签包裹着的内容将被分发 -->
    <!-- 思考下:是否可以在 fly-table组件中直接书写这段代码? -->
    <template slot-scope="{ row, col }">
            <span v-if="col.prop !== 'operate'">
                 {{ row[col.prop] }}
              </span>
        <button
                class="btn btn-text"
                v-else
                @click="handleMarked(row)">
            切换标记
        </button>
    </template>
</fly-table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script type="text/javascript">
    let FlyTable = {
        props: {  // 组件接收从父组件传入的数据
            fields: {
                type: Array,
                default () {
                    return []
                }
            },
            goods: {
                type: Array,
                default () {
                    return []
                }
            }
        },
        template: function () {
            return '<table class=" fly-table">\n' +
                '    <tr>\n' +
                '      <th\n' +
                '        v-for="(col, cIndex) in fields"\n' +
                '        :key="cIndex">\n' +
                '        {{ col.label }}\n' +
                '      </th>\n' +
                '    </tr>\n' +
                '    <tr\n' +
                '      v-for="(row, rIndex) in goods"\n' +
                '      :key="rIndex"\n' +
                '      :style="{color: row.isMarked ? \'#ea4335\' : \'\'}">\n' +
                '      <td\n' +
                '        style="border-top: 1px solid #eee"\n' +
                '        v-for="(col, cIndex) in fields"\n' +
                '        :key="cIndex">\n' +
                // slot应写在子组件中,用于接收父组件分发的内容
                '        <slot :row="row" :col="col"></slot>\n' +
                '      </td>\n' +
                '    </tr>\n' +
                '  </table>'
        }()
    }
    // 声明 Vue 实例
    let vm = new Vue({
        el: '#app',
        components: { FlyTable },
        data () {
            return {
                fields: [
                    {
                        label: '名称',
                        prop: 'name'
                    },
                    {
                        label: '数量',
                        prop: 'quantity'
                    },
                    {
                        label: '价格',
                        prop: 'price'
                    },
                    {
                        label: '',
                        prop: 'operate'
                    }
                ],
                goods: [
                    {
                        name: '苹果',
                        quantity: 200,
                        price: 6.8,
                        isMarked: false
                    },
                    {
                        name: '西瓜',
                        quantity: 50,
                        price: 4.8,
                        isMarked: false
                    },
                    {
                        name: '榴莲',
                        quantity: 0,
                        price: 22.8,
                        isMarked: false
                    }
                ]
            }
        },
        methods: {
            handleReverse () {
                this.goods.reverse()
            },
            handleMarked (row) {
                row.isMarked = !row.isMarked
            }
        }
    })
</script>

</body>

在这里插入图片描述
在这里插入图片描述
这段代码中定义了fly-table组件,它接收fields和goods属性,用以动态显示表格数据。在调用fly-table时,还提供了倒序数组的功能,并使用slot-scope根据数据的不同进行多态的视图渲染。显然,在之前的代码改造之后,fly-table组件的复用性更好

组件的缓存

keep-alive是一个抽象组件,即它既不渲染任何DOM元素,也不会出现在组件结构树中。我们可以使用它缓存一些非动态的组件实例(没有或不需要数据变化),以保留组件状态或减少重新渲染的开销。keep-alive应出现在组件被移除之后需要再次挂载的地方,比如使用动态组件时:
 
 


或者使用v-if时:




它还可以接收include和exclude两个props属性:
●include字符串或正则表达式。只有匹配的组件会被缓存。 ●exlude字符串或正则表达式。任何被匹配的组件将不会被缓存。
当组件在keep-alive内被切换时,它的activated和deactivated这两个生命周期钩子函数将会被执行。

过渡效果

单节点的过渡

Vue提供了标签为transition的内置组件,在下列情形中,我们可以给任何元素和组件添加进入/离开时的过渡动画:
  ●元素或组件初始渲染时
  ●元素或组件显示/隐藏时(使用v-if或v-show进行条件渲染时)
  ●元素或组件切换时 Vue允许用户使用CSS和JS两种方式来定义过渡效果。 在使用CSS过渡时,我们需要预置符合Vue规则的带样式的类名,这些类名用于定义过渡不同阶段时的样式:
  ●v-enter:定义进入过渡的开始状态。在元素被插入前生效,被插入后的下一帧移除。
  ●v-enter-active:定义进入过渡生效时的状态。在整个进入过渡阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以用来定义进入过渡的过程时间、延迟和曲线函数等。
  ●v-enter-to:(Vue 2.1.8及以上版本)定义进入过渡结束时的状态。在元素被插入后的下一帧生效(此时v-enter被移除),在过渡/动画完成之后移除。
  ●v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
  ●v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。 这个类可以被用来定义离开过渡的过程时间、延迟和曲线函数。
  ●v-leave-to:(Vue 2.1.8版及以上版本)定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效(此时v-leave被移除),在过渡/动画完成之后移除。 当实例中存在多个不同的动画效果时,我们可以使用自定义前缀替换v-,比如使用slide-enter替换v-enter,不过这需要赋予transition元素name属性。 下面来看一个示例,代码如下:

<body>
<style>
    /* 在此处声明过渡样式类,从一个状态过渡到另一个状态 */
    .v-enter,
    .v-leave-to {
        opacity: 0;
    }
    .v-enter-active,
    .v-leave-active {
        transition-property: opacity; /* 过渡属性 */
        transition-delay: 100ms;  /* 延迟 */
        transition-duration: 900ms; /* 过渡时长 */
        transition-timing-function: linear; /* 贝塞尔曲线(动画速度曲线) */
    }
    .rotate-enter,
    .rotate-leave-to {
        transform: rotateY(90deg);
    }
    .rotate-enter-active,
    .rotate-leave-active {
        transform-origin: left;
        transition: transform 1s linear;
    }
    </style>
      <div id="app">
      <button @click="isHidden = !isHidden"> {{ isHidden?'显示':'隐藏' }}</button>
    <!-- 默认前缀的过渡 -->
    <transition>
     <p v-if="!isHidden">使用默认前缀的过渡</p>
    </transition>
    <!-- 自定义前缀的过渡,transitionName为变量 -->
    <transition :name="transtionName">
  <p v-if="!isHidden">使用rotate前缀的过渡</p>
 </transition>
    </div>
 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
    <script type="text/javascript">
    // 声明 Vue 实例
  let vm = new Vue({
    el: '#app',
    data () {
    return {
        isHidden: true,
        transtionName: 'rotate' 
        /*// 如果在运行时,将transitionName改为v会怎样?*/
    }
    }
    })
    </script>

      </body>

效果:
在这里插入图片描述
点击显示之后,字体慢慢浮现

除了transition之外,我们还可以使用CSS中的animation,或者直接使用第三方动画库(如Animate.css)来实现过渡动画。借助于Animate.css,我们可以用十分简短的代码来实现一个酷炫的动画效果,
由于这些动画库有着不同的类名规则,无法与Vue默认的类名规则配合使用,因此Vue为其提供了兼容方案,允许用户自定义过渡的类名,这些类名的优先级将高于默认的类名。 我们可以使用以下特性来自定义过渡类名:
●enter-class
●enter-active-class
●enter-to-class
●leave-class
●leave-active-class
●leave-to-class
下面来看一段示例代码:

<body>
   <!-- 引入Animate.css动画库 -->
<link
        rel="stylesheet"
        href="https://cdnjs.cloud flare.com/ajax/libs/animate.css/3.5.2/animate.min.css">
   <!-- 引入Vue -->
   <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
   <style>
       .inline-block {
           display: inline-block;
       }
       .rotate-enter-active {
           animation: selfRotateIn 1s;
       }
       .rotate-leave-active {
           animation: selfRotateOut 1s;
       }
       /* 命名避免与Animate.css冲突 */
       @keyframes selfRotateIn {
           0% {
               opacity: 0;
               transform: rotateZ(-180deg);
           }
           100% {
               opacity: 1;
               transform: rotateZ(0deg);
           }
       }
       @keyframes selfRotateOut {
           0% {
               opacity: 1;
               transform: rotateZ(0deg);
           }
           100% {
               opacity: 0;
               transform: rotateZ(180deg);
           }
       }
       </style>
         <div id="app">
                      <button @click="isHidden = !isHidden">
       {{ isHidden ? '显示' : '隐藏' }}
       </button>
       <!-- 自定义的动画 -->
       <transition name="rotate">
<span class="inline-block" v-if="!isHidden">自定义的动画</span>
    </transition>
       <!-- animate.css的动画 -->
       <transition
        name="custom"
       enter-active-class="animated rotateIn"
       leave-active-class="animated rotateOut">
  <span class="inline-block" v-if="!isHidden">animate.css动画</span>
                                                                                                        <script type="text/javascript">
       // 声明 Vue 实例
          let vm = new Vue({
       el: '#app',
       data () {
       return {
           isHidden: true
       }
       }
       })
       </script>
        </body>

效果:
在这里插入图片描述
点击显示时字体旋转浮现

节选自–《vue.js从入门到实战》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值