美文网首页Vue.js开发技巧Vue技术前端开发那些事儿
【vue】 6.0 动态组件、slot插槽、单个元素动画

【vue】 6.0 动态组件、slot插槽、单个元素动画

作者: bobokaka | 来源:发表于2021-05-31 09:03 被阅读0次

    插槽和具名插槽

    比如说同一个组件如下代码:

      const app = Vue.createApp({
        template: `
            <myform/>
            <myform/>
        `
        });
    
         app.component('myform', {
        methods:{
        handleClick(){
            alert(123)
        },
        template: `
          <div>
            <div @click="handleClick">提交</div>
          </div>
        `
      });
    

    两个组件,同样是点击事件,但是第一个想div快点击,第二个是button点击,怎么办?
    这时候就用到插槽(动态组件),直接使用slot,但是slot是无法绑定事件的。

      const app = Vue.createApp({
        template: `
            <myform>
                <div>提交</div>
            </myform>
            <myform>
                  <button>提交</div>
            </myform>
        `
        });
    
         app.component('myform', {
        methods:{
        handleClick(){
            alert(123)
        },
        template: `
          <div>
            <input/>
            <slot></slot>
          </div>
        `
      });
    

    绑定事件可以如下编写:

      const app = Vue.createApp({
        template: `
            <myform>
                <div>提交</div>
            </myform>
            <myform>
                  <button>提交</div>
            </myform>
        `
        });
    
         app.component('myform', {
        methods:{
        handleClick(){
            alert(123)
        },
        template: `
          <div>
            <input/>
            <span @click="handleClick">
                    <slot></slot>
            </span>
          </div>
        `
      });
    

    父模版里调用的数据属性,使用的都是父模版里的数据
    子模版里调用的数据属性,使用的都是子模版里的数据
    slot也可以设定默认值,当没有模块传入时显示默认模块。

      const app = Vue.createApp({
        template: `
            <myform>
                <div>提交</div>
            </myform>
            <myform>
                  <button>提交</div>
            </myform>
             <myform>
            </myform>
        `
        });
    
         app.component('myform', {
        methods:{
        handleClick(){
            alert(123)
        },
        template: `
          <div>
            <input/>
            <slot>default value</slot>
          </div>
        `
      });
    

    当我们想更自由的处理插槽的时候,可以如下编写代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>lesson 20</title>
      <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
      <div id="root"></div>
    </body>
    <script>
      // slot 插槽
      // slot 中使用的数据,作用域的问题
      // 父模版里调用的数据属性,使用的都是父模版里的数据
      // 子模版里调用的数据属性,使用的都是子模版里的数据
      // 具名插槽
      const app = Vue.createApp({
        template: `
          <layout>
            <template v-slot:header>
              <div>header</div>
            </template>
            <template v-slot:footer>
              <div>footer</div>
            </template>
          </layout>
        `
      });
    
      app.component('layout', {
        template: `
          <div>
            <slot name="header"></slot>
            <div>content</div>
            <slot name="footer"></slot>
          </div>
        `
      });
    
      const vm = app.mount('#root');
    </script>
    </html>
    
    
    动态组件
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    <style type="text/css">
      
        *{
          margin: 0px;
          padding: 0px;
        }
    
        html,body{
          width: 100%;
          height: 100%;
        }
       footer ul {
        display: flex;
        position: fixed;
        left: 0px;
        bottom: 0px;
        width: 100%;
        height: 40px;
       }
    
       footer ul li {
        flex: 1;
        text-align: center;
        list-style: none;
        height: 40px;
        line-height: 40px;
        background: gray;
       }
    
    
       .bounce-enter-active {
         animation: bounce-in .5s;
       }
       .bounce-leave-active {
         animation: bounce-in .5s reverse;
       }
       @keyframes bounce-in {
         0% {
           transform: translateX(100px);
           opacity: 0;
         }
         
         100% {
           transform: translateX(0px);
           opacity: 1;
         }
       }
    </style>
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
        <div id="box">
           <keep-alive>
             <component :is="who"></component>
           </keep-alive>
           <footer>
             <ul>
               <li><a @click="who='home'">首页</a></li>
               <li><a @click="who='list'" >列表页</a></li>
               <li><a @click="who='shopcar'">购物车页面</a></li>
             </ul>
           </footer>
        </div>
       
    
        <script type="text/javascript">
          //babel-loader  ES6=>ES5
        
    
          var home= {
            template:`<div>
              home
              <input type="text"/>
            </div>`
          }
    
          var list= {
            template:`<div>
              list
            </div>`
          }
    
          var shopcar= {
            template:`<div>
              shopcar
            </div>`
          }
    
    
            var vm = new Vue({
            el:"#box",
            data:{
                // isHomeShow:true,
                // isListShow:false,
                // isShopcarShow:false
                who:"home"
            },
            components:{
              home, 
              list,
              shopcar
            }
          })
    
        </script>
    </body>
    </html>
    
    slot(插槽)

    a、b就是具名插槽,另一个333就是“单个slot”

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
        <div id="box">
          <hello>
            <ul slot="a">
              <li>111</li>
              <li>111</li>
              <li>111</li>
              <li>111</li>
            </ul>
            <ul slot="b">
              <li>222</li>
              <li>222</li>
              <li>222</li>
              <li>222</li>
            </ul>
    
            <ul >
              <li>333</li>
              <li>333</li>
              <li>333</li>
              <li>333</li>
            </ul>
          </hello>
    <!--  <swiper>
                
          </swiper> -->
        </div>
       
    
        <script type="text/javascript">
        
          var hello = {
                template:`<div>
                    <slot name="b"></slot>
                    hello
                    <slot name="a"></slot>
    
                    <slot></slot>
                </div>`
          }
    
    
           new Vue({
            el:"#box",
            data:{
            },
            components:{
              hello
            }
           })
        </script>
    </body>
    </html>
    
    单个元素的动画
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
        <div id="box">
            <navbar>
              <button @click="isShow = !isShow">show/hide</button>
            </navbar>
            <sidebar v-show="isShow"></sidebar>
    
            <swipe>
              <li>444444</li>
              <li>555555</li>
              <li>666666</li>
            </swipe>
        </div>
       
       
    
        <script type="text/javascript">
            //子组件
           Vue.component("navbar",{
            template:`<div>
    
              navbar--<slot></slot>
            </div>`
           })
    
    
           Vue.component("sidebar",{
            template:`<div>
    
              sidebar
              <ul>
                <li>1111</li>
                <li>1111</li>
                <li>1111</li>
                <li>1111</li>
                <li>1111</li>
                <li>1111</li>
                <li>1111</li>
              </ul>
            </div>`
           })
    
    
           Vue.component("swipe",{
            template:`<div>
              <ul>
                  <slot></slot>
              </ul>
    
            </div>`
            
    
           })
           
            var vm = new Vue({
              el:"#box",
              data:{
                isShow:false
              }
            })
          
    
        </script>
    </body>
    </html>
    
    transition动画过渡效果
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    <style>
    
      .kerwinfade-enter-active, .kerwinfade-leave-active {
        transition: all 1.5s;
      }
      .kerwinfade-enter, .kerwinfade-leave-to /* .fade-leave-active below version 2.1.8 */ {
        opacity: 0;
        transform: translateX(100px);
      }
    
    
      .bounce-enter-active {
        animation: bounce-in .5s;
      }
      .bounce-leave-active {
        animation: bounce-in .5s reverse;
      }
      @keyframes bounce-in {
        0% {
          opacity: 0;
          transform: translateX(100px);
        }
    
        100% {
          opacity: 1;
          transform: translateX(0px);
        }
      }
    
    </style>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css" rel="stylesheet" type="text/css">
    
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
    
        <!-- <h1 class="animated heartBeat infinite ">1111111111111</h1> -->
    
        <div id="box">
            <button @click="isShow= !isShow">click</button>
    
            <transition name="kerwinfade">
                <p v-show="isShow">11111111111111111</p>
            </transition>
    
    
            <transition name="bounce">
                <p v-show="isShow">2222222222222</p>
            </transition>
    
    
            <transition enter-active-class="animated bounceInRight" leave-active-class="animated bounceOutRight">
                <p v-show="isShow">33333333333333333</p>
            </transition>
        </div>
    
        <script>
          var vm = new Vue({
            el:"#box",
            data:{
              isShow:true
            }
          })
    
    
          //obox1.addEventListern("transitionEnd")
          //obox2.addEventListern("animationEnd")
        </script>
    </body>
    </html>
    
    以上手写的也有好的框架可以直接使用
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    <style>
      .kerwin-enter-active, .kerwin-leave-active {
        transition: all .5s
      }
      .kerwin-enter, .kerwin-leave-to /* .fade-leave-active in below version 2.1.8 */ {
        opacity: 0;
        transform: translateX(100px);
      }
    
    
    
       .bounce-enter-active {
        animation: bounce-in .5s;
      }
      .bounce-leave-active {
        animation: bounce-in .5s reverse;
      }
      @keyframes bounce-in {
        
        0%{
          transform: translateX(100px);
          opacity: 0;
        }
    
        100%{
          transform: translateX(0px);
          opacity: 1;
        }
      }
    </style>
    <link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
    
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
    
    
        <!-- <div class="animated  hinge infinite">1111111111111</div> -->
        <div id="box">
            <button @click="isShow= !isShow">click</button>
    
            <transition name="bounce" appear>
              <p v-show="isShow">11111111111</p>
    
            </transition>
    
        </div>
    
        <script>
          var vm = new Vue({
            el:"#box",
            data:{
              isShow:true
            }
          })
    
        </script>
    </body>
    </html>
    
    多个元素的组件动画
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    <style>
      
    .bounce-enter-active {
      animation: bounce-in .5s;
    }
    .bounce-leave-active {
      animation: bounce-in .5s reverse;
    }
    @keyframes bounce-in {
      0% {
        transform: translateX(100px);
        opacity: 0;
      }
      
      100% {
        transform: translateX(0px);
        opacity: 1;
      }
    }
    </style>
    <link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
    
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
    
    
        <!-- <div class="animated  hinge infinite">1111111111111</div> -->
        <div id="box">
            <button @click="isShow= !isShow">click</button>
    
            <transition name="bounce" mode="out-in">
              <div v-if="isShow" key="1">111111</div>
              <div v-else key="2">222222</div>
            </transition>
        </div>
    
        <script>
          var vm = new Vue({
            el:"#box",
            data:{
              isShow:true
            }
          })
    
    
    
          // {
          //   tag:"div",
          //   text:"111111"
          // }
    
    
          // {
          //   tag:"p",
          //   text:"222222"
          // }
    
    
          /* Vue 为了减少对于dom 的操作
    
            (1)  key 目的:为了重用
    
                key值相同, 就重用
                key值不同,就不重用
    
            (2)  v-if v-else 如果标签相同,就重用,如果标签不同, 就不重用
           */
    
        </script>
    </body>
    </html>
    

    transition支持两个属性name和mode,其中mode只支持2个值:in-out 、out-in

    多个组件过渡
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    <style type="text/css">
      
        *{
          margin: 0px;
          padding: 0px;
        }
    
        html,body{
          width: 100%;
          height: 100%;
          overflow-x: hidden;
        }
       footer ul {
        display: flex;
        position: fixed;
        left: 0px;
        bottom: 0px;
        width: 100%;
        height: 40px;
       }
    
       footer ul li {
        flex: 1;
        text-align: center;
        list-style: none;
        height: 40px;
        line-height: 40px;
        background: gray;
       }
    
    
       .bounce-enter-active {
         animation: bounce-in .5s;
       }
       .bounce-leave-active {
         animation: bounce-in .5s reverse;
       }
       @keyframes bounce-in {
         0% {
           transform: translateX(100px);
           opacity: 0;
         }
         
         100% {
           transform: translateX(0px);
           opacity: 1;
         }
       }
    </style>
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
        <div id="box">
           <keep-alive>
            <transition name="bounce" mode="out-in">
             <component :is="who"></component>
            </transition>
           </keep-alive>
           <footer>
             <ul>
               <li><a @click="who='home'">首页</a></li>
               <li><a @click="who='list'" >列表页</a></li>
               <li><a @click="who='shopcar'">购物车页面</a></li>
             </ul>
           </footer>
        </div>
       
    
        <script type="text/javascript">
          //babel-loader  ES6=>ES5
        
    
          var home= {
            template:`<div>
              home
              <input type="text"/>
            </div>`
          }
    
          var list= {
            template:`<div>
              list
            </div>`
          }
    
          var shopcar= {
            template:`<div>
              shopcar
            </div>`
          }
    
    
          var vm = new Vue({
            el:"#box",
            data:{
                // isHomeShow:true,
                // isListShow:false,
                // isShopcarShow:false
                who:"home"
            },
            components:{
              home, 
              list,
              shopcar
            }
          })
    
        </script>
    </body>
    </html>
    
    多个列表过渡
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
            <title>Examples</title>
            <meta name="description" content="">
            <meta name="keywords" content="">
            <link href="" rel="stylesheet">
            <script type="text/javascript" src="lib/vue.js"></script>
    
            <style>
                .bounce-enter-active {
                    animation: bounce-in .5s;
                }
    
                .bounce-leave-active {
                    animation: bounce-in .5s reverse;
                }
    
                @keyframes bounce-in {
                    0% {
                        transform: translateX(100px);
                        opacity: 0;
                    }
    
                    100% {
                        transform: translateX(0px);
                        opacity: 1;
                    }
                }
            </style>
        </head>
        <body>
            <div id="box">
                <input type="text" v-model="mytext" />
                <button @click="handleClick()">add</button>
    
                <!-- <ul> -->
                <transition-group tag="ul" name="bounce">
                    <li v-for="item,index in datalist" :key="item">
                        {{item}}--<button @click="handleDelClick(index)">del</button>
                    </li>
                </transition-group>
                <!-- </ul> -->
            </div>
    
            <script type="text/javascript">
                var vm = new Vue({
                    el: "#box",
                    data: {
                        mytext0: 111111,
                        mytext: 111111,
                        datalist: []
                    },
    
                    methods: {
                        handleClick: function() {
                            this.datalist.push(this.mytext);
                            this.mytext += this.mytext0
                        },
    
                        handleDelClick(index) {
                            console.log("del-click", index)
    
                            this.datalist.splice(index, 1); //删除
                        }
                    }
                })
    
                // 新老虚拟dom对比的 时候 会 使用 diff 算法。
                // 
                // 
    
                // 
                //    li -1111-  1111
                //    li -2222-  2222
                //    li- 3333- 3333
                //    
                //    
                //    li -1111-  1111
                //    li -33333- 3333
            </script>
        </body>
    </html>
    
    可复用过渡
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Examples</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link href="" rel="stylesheet">
    
    <style>
      .bounce-enter-active {
        animation: bounce-in .5s;
      }
      .bounce-leave-active {
        animation: bounce-in .5s reverse;
      }
      @keyframes bounce-in {
        0% {
          transform: translateX(-100%);
          opacity: 0;
        }
        
        100% {
          transform: translateX(0px);
          opacity: 1;
        }
      }
    </style>
    <script type="text/javascript" src="lib/vue.js"></script>
    </head>
    <body>
        <div id="box">
            <navbar @myevent="control"></navbar>
           
            <sidebar v-show="isShow"></sidebar>
            
        </div>
       
       
    
        <script type="text/javascript">
            //子组件
           Vue.component("navbar",{
            template:`<div>
    
              navbar--<button @click="handleClick">show/hide</button>
            </div>`,
    
            methods:{
              handleClick(){
                this.$emit("myevent");
              }
            }
           })
    
    
           Vue.component("sidebar",{
            template:`
             <transition name="bounce">
            <div style="background:black;color:white;width:300px;">
    
              sidebar
              <ul>
                <li>1111</li>
                <li>1111</li>
                <li>1111</li>
                <li>1111</li>
                <li>1111</li>
                <li>1111</li>
                <li>1111</li>
              </ul>
            </div>
            </transition>
            `
           })
    
           
            var vm = new Vue({
              el:"#box",
              data:{
                isShow:false
              },
              methods:{
                control(){
                  this.isShow = !this.isShow;
                }
              }
            })
          
    
        </script>
    </body>
    </html>
    

    案例2:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>lesson 23</title>
      <style>
        /*  动画
        @keyframes leftToRight {
          0% {
            transform: translateX(-100px);
          }
          50% {
            transform: translateX(-50px);
          }
          0% {
            transform: translateX(0px);
          }
        }
        .animation {
          animation: leftToRight 3s;
        } */
    
        /* 过渡
        .transition {
          transition: 3s background-color ease;
        }
        .blue {
          background: blue;
        }
        .green {
          background: green;
        } */
    
        .transition {
          transition: 3s background-color ease;
        }
    
      </style>
      <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
      <div id="root"></div>
    </body>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            styleObj: {
              background: 'blue'
            }
          }
        },
        methods: {
          handleClick() {
            if(this.styleObj.background === 'blue') {
              this.styleObj.background = 'green';
            }else {
              this.styleObj.background = 'blue'
            }
          }
        },
        template: `
          <div>
            <div class="transition" :style="styleObj">hello world</div>
            <button @click="handleClick">切换</button>
          </div>
        `
      });
    
      const vm = app.mount('#root');
    </script>
    </html>
    

    单元素、单组件的出场入场,vue提供transition 标签。

    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>lesson 24</title>
      <style>
        @keyframes shake {
          0% {
            transform: translateX(-100px)
          }
          50% {
            transform: translateX(-50px)
          }
          100% {
            transform: translateX(50px)
          }
        }
        .hello-leave-active {
          animation: shake 3s;
        }
        .hello-enter-active {
          animation: shake 3s;
        }
      </style>
      <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
      <div id="root"></div>
    </body>
    <script>
      // 单元素,单组件的入场出场动画
      const app = Vue.createApp({
        data() {
          return {
            show: false
          }
        },
        methods: {
          handleClick() {
            this.show = !this.show;
          }
        },
        template: `
          <div>
            <transition name="hello">
              <div v-if="show">hello world</div>
            </transition>
            <button @click="handleClick">切换</button>
          </div>
        `
      });
    
      const vm = app.mount('#root');
    </script>
    </html>
    

    相关文章

      网友评论

        本文标题:【vue】 6.0 动态组件、slot插槽、单个元素动画

        本文链接:https://www.haomeiwen.com/subject/xcnssltx.html