小黑子的——vue从入门到入土过程:第二章

VUE2.0——VUE3.0系列第二章

1. 旧版slot

单个插槽, <slot></slot>
具名插槽 <slot name="a"></slot>
slot=‘插槽名’ slot-scope=“子组件传递过来的数据对象

slot的作用
有了slot,那么组件的复用性则会提升,可以在组件中多放置一些插槽,在不同的文档中使用该组件时,插入不同的东西

在父组件中的标签用插槽引入子组件中也可以在父组件中进行编译

可以在组件里面添加DOM结构

插槽的意义:扩展组件能力,提高组件的复用性

1.1 没有给slot给名字时,单个插槽

有几个slot,那么里面的全部DOM结构就会复制几遍

  <script src="./vue.js/vue2.js"></script>
  <div id="box">
      <child>
        <div>11111111111111</div>
        <div>22222222222222</div>
        <div>33333333333333</div>
      </child>
  </div>


  <script type="text/javascript">
    Vue.component("child", {
      template: `
	<div>
    child
		<slot></slot>
		<slot></slot>
		<slot></slot>
	</div>
`
    })
    new Vue({
      el:"#box"
    })
</script>

在这里插入图片描述

1.1 给slot给名字时,具名插槽

则会按照名称的顺序来表达出来

  <script src="./vue.js/vue2.js"></script>
  <div id="box">
      <child>
        <div slot="a">11111111111111</div>
        <div slot="b">22222222222222</div>
        <div slot="c">33333333333333</div>
        <div>4444444444</div>
      </child>
  </div>


  <script type="text/javascript">
    Vue.component("child", {
      template: `
	<div>
    child
		<slot name="a"></slot>
		<slot name="b"></slot>
		<slot name="c"></slot>
		<slot></slot>
	</div>
`
    })
    new Vue({
      el:"#box"
    })
</script>

在这里插入图片描述

2. 新版slot

  1. 具名插槽的缩写 v-slot:替换为字符#
  2. template配合v-slot:/#使用
  <script src="./vue.js/vue2.js"></script>
  <div id="box">
    <!-- 当前组件或者节点 在哪个模板中,就能访问哪个模板状态 -->
    <child>
      <template v-slot:a>
        <div>1111111111</div>
      </template>

      <template #b>
        2222222222222222222
      </template>

      <div slot="c">33333333333333</div>
      <div>44444444444444</div>
    </child>

    <navbar>
      <template #left>
        <button>aaa</button>
      </template>
      <template #right>
        <i class="iconfont icon-all">字体图标</i>
      </template>
    </navbar>

  </div>

  <script>
    // 插槽的意义 : 扩展组件能力, 提高组件的复用性
    Vue.component("navbar", {
      template: `
      
        <div>
          <slot name="left"></slot>
          <span>navbar</span>  
          <slot name="right"></slot>
        </div>
      `
    })
    
    Vue.component("child", {
      template: `
        <div>
          child
          <slot name="a"></slot>
          <slot name="b"></slot>
          <slot name="c"></slot>
          <slot></slot>
        </div>
      `
    })
    new Vue({
      el: "#box"
    })
  </script>

在这里插入图片描述

3. 插槽版抽屉案例

  <script src="./vue.js/vue2.js"></script>

  <div id="box">
   <navbar>
    <button @click="isShow=!isShow">click</button>
   </navbar>
   <sidebar v-show="isShow"></sidebar>
  </div>

  <script>
    Vue.component("navbar",{

      template:`
        <div>
          nabbar- <slot></slot>
        </div>
      `
    })
    
    Vue.component("sidebar",{
      template:`
       <ul style="background-color: yellow;width:200px;height:500px;">
        <li>首页</li>
        <li>钱包</li>
        <li>设置</li>
      </ul>
      `
    })

    new Vue({
      el: "#box",
      data:{
        isShow:false
      }
    })
  </script>

在这里插入图片描述

在这里插入图片描述

4. 过渡效果

过渡其实就是一个淡入淡出的效果。Vue在元素显示与隐藏的过渡中,提供了 6 个 class 来切换:

  • v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
  • v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
  • v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter
    被移除),在过渡/动画完成之后移除。
  • v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
  • v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
  • v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。

在这里插入图片描述
对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my-transition">,那么 v-enter 会替换为 my-transition-enter。

作用:

为了让vue 页面效果展示时高端点、友好点,我们可以适当的加入一些过渡效果

使用规则:

  1. 在vue 中,如果要让某个组件(元素)添加过渡效果,就必须让该组件(元素)包裹在<transition></transition>
    元素中。该元素有个name 属性,用于标识作用。此外,我们还要去设置过渡效果css
  2. 这个标签只能过渡一个标签
  <script src="./vue.js/vue2.js"></script>

  <style>
    /* 进场动画 */
    .kerwin-enter-active{
      animation: aaa 1.5s;
    }
    /* 出场动画 */
    .kerwin-leave-active{
      animation: aaa 1.5s reverse;
    }
    @keyframes aaa{
      0%{
        opacity: 0;
        transform: translateX(100px);
      }

      100%{
        opacity: 1;
        transform: translateX(0px);
      }
    }
  </style>

  <div id="box">
   <button @click="isShow=!isShow">change</button>


    <transition enter-active-class="kerwin-leave-acitve" leave-active-class="kerwin-leave-active">
      <div v-if="isShow">11111111111111</div>
    </transition>

    <transition name="kerwin" appear>
          <!-- 让第一次出现动画 -->
      <div v-if="isShow">222222222222</div>
    </transition>

  </div>

  <script>
    new Vue({
      el: "#box",
      data:{
        isShow:true
      }
    })
  </script>

在这里插入图片描述
在这里插入图片描述

  <script src="./vue.js/vue2.js"></script>

  <style>
    /* 进场动画 */
    .kerwin-enter-active{
      animation: aaa 1.5s;
    }
    /* 出场动画 */
    .kerwin-leave-active{
      animation: aaa 1.5s reverse;
    }
    @keyframes aaa{
      0%{
        opacity: 0;
        transform: translateX(100px);
      }

      100%{
        opacity: 1;
        transform: translateX(0px);
      }
    }
  </style>

  <div id="box">
   <button @click="isShow=!isShow">change</button>

   <transition name="kerwin">
    <!-- <div v-if="isShow" >11111111111111</div>
    <div v-else="isShow" >2222222222222</div> 
    两个div点击时不出现想要的动画效果
  -->
    <div v-if="isShow" key="1">11111111111111</div>
    <div v-else="isShow" key="2">2222222222222</div>
   </transition>
  </div>

  <script>
    var vm =new Vue({
      el: "#box",
      data:{
        isShow:false
      }
    })
  </script>

在这里插入图片描述

5. 过渡中的diff算法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • Vue的diff算法会使改变前与改变后进行父对父,子对子对比
  • 在改变过渡效果时如果使相同标签对比,则可能会用diff算法,直接将不同的东西改变,导致效果无法看到
  • 而如果标签不相同,那么diff算法就认为发生了翻天覆地的改变,使用过渡效果,两个标签替换时,就会先删除第一个再让第二个加载
<button @click="isShow = !isShow" >change</button>
<transition name="kerwin" mode=”out-in>
	<div v-if="isShow">111111111111111</div>
	<p v-else >2222222222222222222222222</p>
</transition>


<!-- 
	<button @click="isShow = !isShow" >change</button>
	<transition name="kerwin" mode=”out-in>
	<div v-if="isShow" key="1">111111111111111</div>
	<div v-else key="2">2222222222222222222222222</div>
	</transition>
 -->

6. 列表过度

属性

mode=“out-in”:先走再来
mode=“in-out”:先来再走

组件过渡:组件过渡可以使用动态组件,在动态组件上加上<transition>标签即可
列表过渡:<transition-grop>可以添加多个标签,需要给标签加key值
<transition-grop>有tag属性,可以指定转化成的一个标签
在这里插入图片描述

  <script src="./vue.js/vue2.js "></script>
  <style>
    /* 进场动画 */
    .kerwin-enter-active {
      animation: aaa 1.5s;
    }

    /* 出场动画 */
    .kerwin-leave-active {
      animation: aaa 1.5s reverse;
    }

    @keyframes aaa {
      0% {
        opacity: 0;
        transform: translateX(100px);
      }

      100% {
        opacity: 1;
        transform: translateX(0px);
      }
    }
  </style>

  <div id="box">
    <!--双向绑定了一个输入框的value -->
    <input type="text" v-model="mytext" />
    <!--  {{mytext}} -->
    <button @click="handleAdd()">add</button>

    <!-- 当被删除完之后显示空空如也-->
    <div v-show="!datalist.length">待办事项空空如也</div>

    <transition-group v-show="datalist.length" name="kerwin" tag="ul">

      <li v-for="(item,index) in datalist" :key="item">
        {{item}}--{{index}}
        <button @click="handeleDel(index)">del</button>
      </li>

    </transition-group>

  </div>

  <script>
    var vm = new Vue({
      el: "#box",
      data: {
        mytext: "11111111",
        datalist: ["1111", "2222", "3333"]
      },
      methods: {
        handleAdd() {
          console.log("获取value", this.mytext)
          this.datalist.push(this.mytext)

          //清空输入框的value
          this.mytext = " "
        },
        handeleDel(index) {
          console.log("del", index)
          this.datalist.splice(index, 1)//删除数组元素
        }
      }
    })
  </script>

在这里插入图片描述

7. 可复用过渡

将动画封装在一个组件中,即可以做到复用过渡

  <style>
    .left {}
    /* 在mode填写修改从左边还是从右边 */
    .right {
      position: fixed;
      right: 0px;
      top: 0px;
    }

    /* 进场动画 */
    .left-enter-active {
      animation: aaa 1.5s;
    }

    /* 出场动画 */
    .left-leave-active {
      animation: aaa 1.5s reverse;
    }

    @keyframes aaa {
      0% {
        opacity: 0;
        transform: translateX(-100%);
      }

      100% {
        opacity: 1;
        transform: translateX(0px);
      }
    }


    .right-enter-active {
      animation: bbb 1.5s;
    }

    /* 出场动画 */
    .right-leave-active {
      animation: bbb 1.5s reverse;
    }

    @keyframes bbb {
      0% {
        opacity: 0;
        transform: translateX(100px);
      }

      100% {
        opacity: 1;
        transform: translateX(0px);
      }
    }
  </style>
</head>

<body>
  <div id="box">
    <navbar @myevent="handleEvent"></navbar>
    <sidebar v-show="isShow" mode="right"></sidebar>
  </div>
  <script>
    Vue.component("navbar", {

      template: `
            <div>
              nabbar-<button @click="handleClick">click</button>  
            </div>
          `,
      methods: {
        handleClick() {
          // 通知父组件 取反 isShow - 子传父 依靠 事件
          this.$emit("myevent")
        }
      }
    })

    Vue.component("sidebar", {
      props: ["mode"],
      template: `
          <transition :name="mode">
            <ul style="background-color: yellow;width: 200px;height: 500px;" :class="mode">
              <li>首页</li>
              <li>钱包</li>
              <li>设置</li>
            </ul>
          </transition>
          `
    })

    new Vue({
      el: "#box",
      data: {
        isShow: false
      },
      methods: {
        handleEvent() {
          console.log("父组件", "1111111")
          this.isShow = !this.isShow
        }
      }
    })
  </script>

在这里插入图片描述

8. 生命周期

什么是生命周期

组件的生命周期指的是:组件从创建 -> 运行(渲染) -> 销毁的整个过程,强调的是一个时间段

什么是Vue 组件生命周期钩子函数
所谓生命周期钩子函数(简称生命周期函数),指的是组件的创建、更新、销毁三个阶段所触发执行的函数。 根据每个阶段触发的钩子函数,我们可以相应的做一些操作,如获取后端接口数据、监听事件、执行事件、执行定时器、移除事件、清理定时器等等。

在这里插入图片描述
什么是钩子函数

简单点来说,钩子函数就是你创建的Vue在初始化、更新数据、销毁时会被自动调用的函数。

八大钩子数分别是:
beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestory,destoryed

面试可能的问题:
说一下vue的生命周期函数,包括每一个生命周期函数在项目中什么时候去用的。

钩子名固定,与data和methods属于平级关系,如果执行相应的方法,会输出一句话

    <div id="app"></div>
    <script>
        var vm=new Vue({
            el: "#app",
            data: {},
            beforeCreate() {console.log("beforeCreate")},
            created() {console.log("created")},
            beforeMount() {console.log("beforeMount")},
            mounted() {console.log("mounted")},
            beforeUpdate() {console.log("beforeUpdate")},
            updated() {console.log("updated")},
            beforeDestroy() {console.log("beforeDestroy")},
            destroyed() {console.log("destroyed")},
            methods: {}
            });
    </script>

在这里插入图片描述

8.1 创建阶段

每个 Vue 组件实例在创建时都会经历一系列初始化步骤——例如,它需要设置数据观察、编译模板、将实例挂载到 DOM 以及在数据更改时更新 DOM。在此过程中,它还运行称为生命周期钩子的函数,让用户有机会在特定阶段添加自己的代码。

调用所有生命周期钩子时,其上下文都指向调用它的当前活动实例。请注意,这意味着在声明生命周期挂钩时应避免使用箭头函数,因为如果这样做,将无法访问组件实例。

在这里插入图片描述

(1). beforeCreate创建前

beforeCreate可以简单的理解为在数据初始化的之前被调用,这时候data和methods尚未没有数据。

在实例处理完所有与状态相关的选项后调用。
在要挂载组件之前调用。

(2). created创建完成

created可以理解为在数据初始化之后被调用,这时候data和methods已经被填充了相应的数据。

调用此钩子时,已设置以下内容:反应式数据、计算属性、方法和观察程序。但是,安装阶段尚未开始,该属性尚不可用


    <div id="app"></div>
    <script>
        var vm=new Vue({
            el: "#app",
            data: {
                msg:"李是神魔念"       //添加msg数据
            },
            beforeCreate() {
                console.log("this= "+this)  
                console.log("this.msg= "+this.msg)
                console.log("this.md= "+this.md)
                console.log("")
                },
            created() {
                console.log("this= "+this)  
                console.log("this.msg= "+this.msg)
                console.log("this.md= "+this.md)              
                console.log("")
                
                },
            methods: {
                md: function(){},        //空方法
            }
            });
    </script>

在这里插入图片描述
结果显示在beforeCreate方法与create方法之间完成了资源的注入。

(3). beforeMount挂载前

调用此钩子时,组件已完成其反应状态的设置,但尚未创建 DOM 节点。它即将首次执行其 DOM 渲染效果。

beforeMount在页面尚未被渲染时使用,也就是Vue的数据没有传到页面。

(4).mounted挂载完成

mounted在页面渲染完成之后使用,也就是此时页面已完全取出Vue中的数据。

组件被视为在以下之后安装:

它的所有同步子组件都已挂载(不包括异步组件或树中的组件)。

它自己的 DOM 树已被创建并插入到父容器中。请注意,如果应用程序的根容器也在文档中,则仅保证组件的 DOM 树在文档中。

此挂钩通常用于执行需要访问组件呈现的 DOM 的副作用,或用于在服务器呈现的应用程序中将与 DOM 相关的代码限制为客户端。

    <div id="app">
        <h1 id="ren">{{msg}}</h1>
    </div>
    <script>
        var vm=new Vue({
            el: "#app",
            data: {
                msg:"李在赣神魔"       //添加msg数据
            },
            beforeMount() {
                let doc = document.querySelector("#ren");//查询到id名为ren的节点
                console.log(doc)   
                console.log("")
            },
            mounted() {
                let doc = document.querySelector("#ren");
                console.log(doc)   
            },
            });
    </script>

在这里插入图片描述
此时,Vue对象中资源已注入完毕,页面也已经渲染完毕,上述四个方法在页面被加载时自动被执行

案例:

      <div id="box">
        
      </div>

    <script type="text/javascript">
      //根组件
      var vm = new Vue({
         el:"#box",
        data:{  
          myname:"van",
          datalist:[]
        },
        // template:`<div>root component--{{myname}}</div>`,支持template,不止子组件可以用
        beforeCreate(){
          console.log("beforeCreate",this.myname)
        },
        created(){
          console.log("created","初始化状态或者挂载到当前实例的一些属性")
          this.myname = this.myname+"11111111" //被拦截的状态

          this.user =localStorage.getItem("user")  // this下面的属性
          // 发ajax
        },

        beforeMount(){
          console.log("beforeMount",this.$el)  // 模板解析之前最后一次修改模板节点。
        },

        mounted(){
          console.log("mounted","拿到真实的dom节点",document.getElementById("box").innerHTML)
          // 依赖于dom创建之后, 才进行初始化工作的插件  (轮播插件)
          // 订阅 bus.$on
          // 发ajax         
        }
      })
    </script>

8.2 更新阶段

(5)beforeUpdate

这个钩子可以用来在 Vue 更新 DOM 之前访问 DOM 状态。在此挂钩中修改组件状态也是安全的。

beforeUpdate在页面更新渲染完成后,DOM树发生改变前被调用

(6)updated

updated在页面DOM树改变后被调用

需要注意的是如果只是改变了dom中的数据(data),未对页面造成任何影响,就不会触发beforeUpdate,updated方法。

父组件的更新钩子在其子组件的钩子之后调用。

此钩子在组件的任何 DOM 更新后调用,这可能是由不同的状态更改引起的。如果您需要在特定状态更改后访问更新的 DOM,请改用 nextTick()。

   <div id="app">
        <h1 id="ren">
            <p v-if="msg"></p>
        </h1>
    </div>
    <script>
        var vm=new Vue({
            el: "#app",
            data: {
                msg:true       //添加msg数据
            },
            beforeUpdate() {
                let a = document.getElementById("ren"); 
                console.log(a.childElementCount)
                console.log("")
            },
            updated() {
                let a = document.getElementById("ren"); 
                console.log(a.childElementCount)
            },
            });
    </script>

在这里插入图片描述

案例:
在这里插入图片描述
在这里插入图片描述

8.3 销毁

(7)beforeDestory

beforeDestory是在Vue组件销毁之前被调用

(8)destoryed

destoryed在Vue组件销毁之后被调用
在这里插入图片描述


    <div id="app">
        <mytest id="child" v-if="flag">
        </mytest>
    </div>
    <script>
        
        let myname = Vue.component('mytest', {
                template: '<p>yes</p>',
 
                beforeDestroy() {
                    console.log("beforeDestroy被执行")
                },
                destroyed() {
                    console.log("destroyed被执行")
                },
            });
        var vm=new Vue({
            el: "#app",
            data: {
                flag: true
            },
            components:{
                "mytest" : myname,
            },
            });
 
    </script>

在这里插入图片描述
案例:

  <script src="./vue.js/vue2.js "></script>
  <div id="box">
    <child v-if="isCreated"></child>
  </div>
  <script>
    Vue.component("child", {
      data() {
        return {
          time: 1000
        }
      },
      created() {
        this.id = null
      },
      mounted() {
        this.id = setInterval(() => {
          console.log("倒计时")
          this.time--
        }, 1000)

        window.onresize = () => {
          console.log("resize")
        }
      },
      template: `
        <div>
            抢购倒计时组件
            <div>{{time}}</div>  
        </div>
      `,

      beforeDestroy() {
        console.log("beforeDestroy", "清除定时器, 事件解绑,,,,")

        clearInterval(this.id)

        window.onresize = null
      },

      destroyed() {
        console.log("destroyed", "清除定时器, 事件解绑,,,,")
      }
    })
    var vm = new Vue({
      el: "#box",
      data: {
        isCreated: true
      }
    })
  </script>

在这里插入图片描述

9. swiper 静态使用

swiper使用需要两个文件,一个是swiper.css,里面规定了一些在这个滑动轮播插件中常用的样式,当然如果愿意的话可以自己定义样式

另外一个是swiper.js这个是插件的主体部分。
这些文件可以在官网查找获取方法
在页面中引入这两个文件之后首先要写基本的html结构

swiper插件:
https://swiper.com.cn/

  <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <style>
    .van {
      height: 500px;
    }
  </style>
  <header>导航</header>

  <div class="swiper van">
    <div class="swiper-wrapper">

    </div>
    <!-- 如果需要分页器 -->
    <div class="swiper-pagination"></div>

    <!-- 如果需要导航按钮 -->
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>

    <!-- 如果需要滚动条 -->
    <!-- <div class="swiper-scrollbar"></div> -->
  </div>

  <footer>底部内容</footer>

  <script>
    //swiper 初始化过早
    setTimeout(()=>{
      var list = ["aaaa","bbbbb","cccc"]
      var newlist = list.map(item=>`
      <div class="swiper-slide">${item}</div>
      `)

      console.log(newlist.join(""))

      var owrapper = document.querySelector(".swiper-wrapper")
      owrapper.innerHTML = newlist.join('')

      //dom插入完之后,再new swiper,就可以解决数据慢载入的问题
      init()
    },1000)


    //初始化 swiper
    function init(){
      new Swiper(".van", {
      // direction:"vertical",//垂直方向
      //如果需要分页器
      pagination: {
        el: '.swiper-pagination',
      },
      loop: true, // 循环模式选项

      // 自动轮播
      autoplay: {
        delay: 2500,
        disableOnInteraction: false,
      },

      // 如果需要前进后退按钮
      navigation: {
        nextEl: '.swiper-button-next',
        prevEl: '.swiper-button-prev',
      },

    })
    }
  </script>

在这里插入图片描述

10. vue-swiper 动态

  <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <script src="./vue.js/vue2.js"></script>

  <div id="box">
    <header>导航-{{myname}}</header>

    <div class="swiper van">
      <div class="swiper-wrapper">
        <div class="swiper-slide" v-for="data in datalist"  :key="data">
          <img :src="data" />
        </div>

      </div>
      <!-- 如果需要分页器 -->
      <div class="swiper-pagination"></div>

    </div>

    <footer>底部内容</footer>
  </div>

  <script>
    //初始化 swiper --初始化过早

    var vm = new Vue({
      el: "#box",
      data: {
        datalist: [],
        myname: "van"
      },
      mounted() {
        //ajax
        setTimeout(() => {
          this.datalist = ["https://static.maizuo.com/pc/v5/usr/movie/e856bdc65507b99800f22e47801fa781.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/47aa5a3ad2ebff403d073288e4365694.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/8b0755547313706883acc771bda7709d.jpg"
          ]
          //过早 

          // 这里输出console.log(document.querySelectorAll(".swiper-slide").length) 为0,是因为dom更新是异步的,虽然状态被父子了

        }, 1000)
        //初始化过早
      },

      updated() {
        console.log(document.querySelectorAll(".swiper-slide").length)

        new Swiper(".van", {
          // direction:"vertical", //垂直
          // 如果需要分页器
          pagination: {
            el: '.swiper-pagination',
          },
          loop: true,
          autoplay: {
            delay: 2500,
            disableOnInteraction: false,
          }
        })

      }
    })
    /*缺点:
      1. 无法复用
      2. 如果当前页面 状态不止datalist一个,其他状态更新, update重新运行,new Swiper 执行多次, 出bug
    */
  </script>

在这里插入图片描述

11. swiper 组件

一、
  <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <script src="./vue.js/vue2.js"></script>

  <div id="box">
    <swiper v-if="datalist.length">
       <!-- 根据数组的长度改变,由之前的为0不创建,到长度不为0开始创建 -->
      <swiper-item v-for="data in datalist" :key="data">
        <img :src="data" />
      </swiper-item>
    </swiper>
    <!-- <swiper :key="datalist.length"></swiper>> -->
  </div>

  <script>
    Vue.component("swiperItem", {
      template: `
      <div class="swiper-slide">
        <slot></slot>
        </div>
      `
    })
    Vue.component("swiper", {
      template: `
      <div class="swiper van">
        <div class="swiper-wrapper">
           <slot></slot>
        </div>

        <div class="swiper-pagination"></div>
       </div>`,
      mounted() {
        new Swiper(".van", {
          // direction:"vertical",//垂直方向
          //如果需要分页器
          pagination: {
            el: '.swiper-pagination',
          },
          loop: true, // 循环模式选项

          // 自动轮播
          autoplay: {
            delay: 2500,
            disableOnInteraction: false,
          }
        })
      },
      destroyed(){

      }
    })

    new Vue({
      el: '#box',
      data:{
        datalist:[]
      },
      mounted() {
        setTimeout(() => {
          this.datalist = ["https://static.maizuo.com/pc/v5/usr/movie/e856bdc65507b99800f22e47801fa781.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/47aa5a3ad2ebff403d073288e4365694.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/8b0755547313706883acc771bda7709d.jpg"
          ]

        }, 1000)

      }
    })
  </script>

在这里插入图片描述

二、
 <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <script src="./vue.js/vue2.js"></script>

  <div id="box">
    <swiper v-if="datalist.length" :loop="false">
      <!-- :loop="false"写的话,轮播到最后不会再直接跳转轮播到第一张, -->
      <swiper-item v-for="data in datalist" :key="data">
        <img :src="data" />
      </swiper-item>
    </swiper>
    <!-- <swiper :key="datalist.length"></swiper>> -->
  </div>

  <script>
    Vue.component("swiperItem", {
      template: `
      <div class="swiper-slide">
        <slot></slot>
        </div>
      `
    })
    Vue.component("swiper", {
      props:{
        loop:{
          type:Boolean,
          default:true
        }
      },
      template: `
      <div class="swiper van">
        <div class="swiper-wrapper">
           <slot></slot>
        </div>

        <div class="swiper-pagination"></div>
       </div>`,
      mounted() {
        new Swiper(".van", {
          // direction:"vertical",//垂直方向
          //如果需要分页器
          pagination: {
            el: '.swiper-pagination',
          },
          loop: this.loop, // 循环模式选项

          // 自动轮播
          autoplay: {
            delay: 2500,
            disableOnInteraction: false,
          }
        })
      },
      destroyed(){

      }
    })

    new Vue({
      el: '#box',
      data:{
        datalist:[]
      },
      mounted() {
        setTimeout(() => {
          this.datalist = ["https://static.maizuo.com/pc/v5/usr/movie/e856bdc65507b99800f22e47801fa781.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/47aa5a3ad2ebff403d073288e4365694.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/8b0755547313706883acc771bda7709d.jpg"
          ]

        }, 1000)

      }
    })
  </script>

在这里插入图片描述

12. vue3组件写法

  <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <script src="./vue.js/vue3.js"></script>

  <div id="box">
    {{myname}}
    <navbar myname="aaaa">
      <div>1111111111111</div>
    </navbar>

    <sidebar></sidebar>
  </div>

  <script>
    // console.log(Vue.component)
    var obj = {
      data(){
        return{
          myname:"van"
        }
      },
      methods:{

      },
      computed:{

      }
    }
    var app = Vue.createApp(obj)
    app.component("navbar",{
      props:["myname"],
      template:`
      navbar-{{myname}}
       <div>navbar</div>
       <slot></slot>
      `
    })
    app.component("sidebar",{
      template:`
       <div>sidebar</div>
      `
    })
    app.mount("#box")
  </script>

在这里插入图片描述

13. vue3 生命周期&轮播

vue3生命周期

  <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <script src="./vue.js/vue3.js"></script>

  <div id="box">
    {{myname}}
    <navbar myname="aaaa">
      <div>1111111111111</div>
    </navbar>

    <sidebar></sidebar>
  </div>

  <script>
    // console.log(Vue.component)
    var obj = {
      data(){
        return{
          myname:"van"
        }
      },
      methods:{

      },
      computed:{

      },
      created(){
        console.log("created")
      },
      beforeMount(){

      },
      mounted(){
        console.log("mounted")
      },
      //生命周期替换
      // beforeDestroy(){
      //   console.log("beforedestroy")
      // },
      // destroyed(){

      // }
      beforeUnmount(){

      },
      unmounted(){

      }
    }
    var app = Vue.createApp(obj)
    app.component("navbar",{
      props:["myname"],
      template:`
      navbar-{{myname}}
       <div>navbar</div>
       <slot></slot>
      `
    })
    app.component("sidebar",{
      template:`
       <div>sidebar</div>
      `
    })
    app.mount("#box")
    //vue2 (类,this)
    //vue3 类(vue》90%一样),hooks(函数式)
  </script>

在这里插入图片描述
vue3轮播

  <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <script src="./vue.js/vue3.js"></script>

  <div id="box">
    <swiper v-if="datalist.length" :loop="false">
      <swiper-item v-for="data in datalist" :key="data">
        <img :src="data" />
      </swiper-item>
    </swiper>

    <!-- <swiper :key="datalist.length"></swiper> -->
  </div>

  <script>
    var obj = {
      data() {
        return {
          datalist: []
        }
      },
      mounted() {
        setTimeout(() => {
          this.datalist = ["https://static.maizuo.com/pc/v5/usr/movie/e856bdc65507b99800f22e47801fa781.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/47aa5a3ad2ebff403d073288e4365694.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/8b0755547313706883acc771bda7709d.jpg"
          ]
        }, 2000)
      }
    }

    var app = Vue.createApp(obj)


    app.component("swiperItem", {
      template: `
      <div class="swiper-slide">
        <slot></slot>
      </div>
    `
    })
    app.component("swiper", {
      props: {
        loop: {
          type: Boolean,
          default: true
        }
      },
      template: `
      <div class="swiper kerwin">
        <div class="swiper-wrapper">
          <slot></slot>
        </div>
        <div class="swiper-pagination"></div>
      </div>`,

      mounted() {
        // console.log("mounted")
        new Swiper(".kerwin", {
          // direction:"vertical", //垂直
          // 如果需要分页器
          pagination: {
            el: '.swiper-pagination',
          },
          loop: this.loop,
          autoplay: {
            delay: 2500,
            disableOnInteraction: false,
          }
        })
      },
      // destroyed() {
      //   // console.log("destroy")

      //   //
      // }
    })

    app.mount("#box")
  </script>

在这里插入图片描述

14. 指令写法

Vue.js的指令是以v-开头的,它们作用于HTML元素,指令提供了一些特殊的特性,将指令绑定在元素上时,指令会为绑定的目标元素添加一些特殊的行为,我们可以将指令看作特殊的HTML特性(attribute)。

指令的作用是当表达式的值改变时,相应地将某些行为应用到 DOM 上。

vue常用指令有:

v-once指令、v-show指令、v-if指令、v-else指令、v-else-if指令、v-for指令、v-html指令、v-text指令、v-bind指令、v-on指令、v-model指令等等。

14.1 自定义指令介绍directives

对普通DOM元素进行底层操作

在这里插入图片描述

  <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <script src="./vue.js/vue2.js"></script>

  <div id="box">
    <div v-hello="'yellow'">111111111111</div>
    <div v-hello="'red'">22222222222</div>
    <div v-hello="whichColor">3333333333</div>
  </div>
  <script>
    //指令 :为了操作底层dom。作者给留方案

    //实际应用--可以通过指令知道什么时候dom创建完成,从而进行依赖dom的库的初始化工作

    Vue.directive("hello", {
      //inserted是指令的生命周期
      inserted(el,binding) {
        //第一次插入到父节点中触发,拿到的binding是一个对象
        console.log("inserted",binding)
        el.style.background = binding.value
      },

      update(el,binding){
        //拿到了最新的dom节点和对象,在修改时可以得到期望的效果
        console.log("update")
        el.style.background = binding.value
      }
    })

    var vm = new Vue({
      el:"#box",
      data:{
        whichColor:"blue"
      }
    })
  </script>

在这里插入图片描述
在这里插入图片描述

15. 指令应用

vue3指令生命周器约==组件生命周期

  <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <script src="./vue.js/vue2.js"></script>

  <div id="box">
    <header>导航-{{myname}}</header>

    <div class="swiper van">
      <div class="swiper-wrapper">
        <div class="swiper-slide" v-for="(data,index) in datalist" :key="data" v-swiper="{
          index:index,
          length:datalist.length
        }">
          <img :src="data" />
        </div>

      </div>
      <!-- 如果需要分页器 -->
      <div class="swiper-pagination"></div>

    </div>

    <footer>底部内容</footer>
  </div>

  <script>
    //初始化 swiper --初始化过早
    Vue.directive("swiper", {
      inserted(el, binding) {
        console.log(binding.value)

        let { index, length } = binding.value
        if (index === length - 1) {
          // new Swiper
            new Swiper(".van", {
              // direction:"vertical", //垂直
              // 如果需要分页器
              pagination: {
                el: '.swiper-pagination',
              },
              loop: true,
              autoplay: {
                delay: 2500,
                disableOnInteraction: false,
              }
            })
        }
      }
    })
    var vm = new Vue({
      el: "#box",
      data: {
        datalist: [],
        myname: "van"
      },
      mounted() {
        //ajax
        setTimeout(() => {
          this.datalist = ["https://static.maizuo.com/pc/v5/usr/movie/e856bdc65507b99800f22e47801fa781.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/47aa5a3ad2ebff403d073288e4365694.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/8b0755547313706883acc771bda7709d.jpg"
          ]
          //过早 

          // 这里输出console.log(document.querySelectorAll(".swiper-slide").length) 为0,是因为dom更新是异步的,虽然状态被父子了

        }, 1000)
        //初始化过早
      }
    })
  </script>

在这里插入图片描述

16. 指令补充&nextTick

在这里插入图片描述
1.

  <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <script src="./vue.js/vue3.js"></script>

  <div id="box">
    <header>导航-{{myname}}</header>

    <div class="swiper van">
      <div class="swiper-wrapper">
        <div class="swiper-slide" v-for="(data,index) in datalist" :key="data" v-swiper="{
          index:index,
          length:datalist.length
        }">
          <img :src="data" />
        </div>

      </div>
      <!-- 如果需要分页器 -->
      <div class="swiper-pagination"></div>

    </div>

    <footer>底部内容</footer>
  </div>

  <script>

    var obj = {
      data(){
        return{
          datalist:[],
          myname:"van"
        }
      },
      mounted() {
        //ajax
        setTimeout(() => {
          this.datalist = ["https://static.maizuo.com/pc/v5/usr/movie/e856bdc65507b99800f22e47801fa781.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/47aa5a3ad2ebff403d073288e4365694.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/8b0755547313706883acc771bda7709d.jpg"
          ]
          //过早 

          // 这里输出console.log(document.querySelectorAll(".swiper-slide").length) 为0,是因为dom更新是异步的,虽然状态被父子了

        }, 1000)
        //初始化过早
      }
    }

   var app= Vue.createApp(obj)

   app.directive("swiper", {
      mounted(el, binding) {
        console.log("111111111111111")

        let { index, length } = binding.value
        if (index === length - 1) {
          // new Swiper
            new Swiper(".van", {
              // direction:"vertical", //垂直
              // 如果需要分页器
              pagination: {
                el: '.swiper-pagination',
              },
              loop: true,
              autoplay: {
                delay: 2500,
                disableOnInteraction: false,
              }
            })
        }
      }
    })
   app.mount("#box")
  </script>

在这里插入图片描述
什么是nextTick()

定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

所以就衍生出了这个获取更新后的DOM的Vue方法。所以放在Vue.nextTick()回调函数中的执行的应该是会对DOM进行操作的 js代码;

理解:nextTick(),是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数

案例:使用this.$nextTick()

  <script src="./swiper/swiper-bundle7.min.js"></script>
  <link rel="stylesheet" href="./swiper/swiper-bundle7.min.css">
  <script src="./vue.js/vue2.js"></script>

  <div id="box">
    <header>导航-{{myname}}</header>

    <div class="swiper van">
      <div class="swiper-wrapper">
        <div class="swiper-slide" v-for="data in datalist"  :key="data">
          <img :src="data" />
        </div>

      </div>
      <!-- 如果需要分页器 -->
      <div class="swiper-pagination"></div>

    </div>

    <footer>底部内容</footer>
  </div>

  <script>
    //初始化 swiper --初始化过早

    var vm = new Vue({
      el: "#box",
      data: {
        datalist: [],
        myname: "van"
      },
      mounted() {
        //ajax
        setTimeout(() => {
          this.datalist = ["https://static.maizuo.com/pc/v5/usr/movie/e856bdc65507b99800f22e47801fa781.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/47aa5a3ad2ebff403d073288e4365694.jpg",
            "https://static.maizuo.com/pc/v5/usr/movie/8b0755547313706883acc771bda7709d.jpg"
          ]

          //等上面节点状态什么时候更新到dom之后,nextTick就会触发一次,而以后再更新,就再触发
          this.$nextTick(()=>{
            console.log("我比updated执行的都晚,并且只执行一次")
            new Swiper(".van", {
              // direction:"vertical", //垂直
              // 如果需要分页器
              pagination: {
                el: '.swiper-pagination',
              },
              loop: true,
              autoplay: {
                delay: 2500,
                disableOnInteraction: false,
              }
            })
          })

        }, 1000)
        //初始化过早
      },
      updated(){
        console.log("updated")
      }

    })
  </script>

在这里插入图片描述
什么时候需要用的nextTick

1、Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中,原因是在created()钩子函数执行的时候DOM其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。

与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载已完成。

  created(){
    let that=this;
    that.$nextTick(function(){  //不使用this.$nextTick()方法会报错
        that.$refs.aa.innerHTML="created中更改了按钮内容";  //写入到DOM元素
    });
  },

2、当项目中你想在改变DOM元素的数据后基于新的dom做点什么,对新DOM一系列的js操作都需要放进Vue.nextTick()的回调函数中;通俗的理解是:更改数据后当你想立即使用js操作新的视图的时候需要使用它

<template>
  <div class="hello">
    <h3 id="h">{{testMsg}}</h3>
  </div>
</template>
 
<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      testMsg:"原始值",
    }
  },
  methods:{
    changeTxt:function(){
      let that=this;
      that.testMsg="修改后的文本值";  //vue数据改变,改变dom结构
      let domTxt=document.getElementById('h').innerText;  //后续js对dom的操作
      console.log(domTxt);  //输出可以看到vue数据修改后DOM并没有立即更新,后续的dom都不是最新的
      if(domTxt==="原始值"){
        console.log("文本data被修改后dom内容没立即更新");
      }else {
        console.log("文本data被修改后dom内容被马上更新了");
      }
    },
 
  }
}
</script>

正确的用法是:vue改变dom元素结构后使用vue.$nextTick()方法来实现dom数据更新后延迟执行后续代码

    changeTxt:function(){
      let that=this;
      that.testMsg="修改后的文本值";  //修改dom结构
       
      that.$nextTick(function(){  //使用vue.$nextTick()方法可以dom数据更新后延迟执行
        let domTxt=document.getElementById('h').innerText; 
        console.log(domTxt);  //输出可以看到vue数据修改后并没有DOM没有立即更新,
        if(domTxt==="原始值"){
          console.log("文本data被修改后dom内容没立即更新");
        }else {
          console.log("文本data被修改后dom内容被马上更新了");
        }
      });
    },

3、在使用某个第三方插件时 ,希望在vue生成的某些dom动态发生变化时重新应用该插件,也会用到该方法,这时候就需要在 $nextTick 的回调函数中执行重新应用插件的方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值