Vue.js开发技巧Vue技术前端开发那些事儿

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

2021-05-31  本文已影响0人  bobokaka

插槽和具名插槽

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

  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>
上一篇下一篇

猜你喜欢

热点阅读