VUE笔记(四)vue的组件

news2024/11/15 16:22:48

一、组件的介绍

1、组件的作用

  • 整个项目都是由组件组成

  • 可以让代码复用:相似结构代码可以做成一个组件,直接进行调用就可以使用,提高代码复用性

  • 可以让代码具有可维护性(只要改一处,整个引用的部分全部都变)

注意点:组件和模块区别

  • 模块仅对逻辑进行复用

  • 组件针对与结构、逻辑、样式进行复用的UI控件

2、组件分类

  • 按作用范围分类

    • 全局组件:项目中所有地方都可以的组件称为全局组件

    • 局部组件(私有组件):仅有该组件才能使用的组件称为局部组件

  • 按照用途来分

    • 页面组件

    • 自定义组件

3、局部组件

使用局部组件的具体步骤

  • 第1步:在src下的components下创建一个单文件组件

    单文件组件由三部分组成

    • template:页面的结构的

    • script:该组件的逻辑代码

    • style:该组件的样式的代码

<template>
    <div class="box">
        <h1>计数器</h1>
        <div>{{num}}</div>
        <div>
            <button @click="num++">+</button>
        </div>
    </div>
</template>
​
<script>
export default {
    data(){
        return{
            num:0
        }
    }
}
</script>
​
<style>
​
    box{
        width: 100px;
        height: 100px;
        border: 1px solid #ccc;
    }
</style>
  • 第2步:通过ES6的import将自定义的组件引入进来

import HelloWorld from './components/HelloWorld.vue'
  • 第3步:注册组件

export default {
  components:{
    HelloWorld
  }
}
  • 第4步:在template模板中直接引用

 <HelloWorld></HelloWorld>
 <hello-world></hello-world>

注意:在template模板的地方如果要引入局部的自定义组件,可以使用短横线命名法或者使用驼峰式命名法均可

4、全局组件

定义全局组件的步骤

  • 首先现在src/components下创建自定义组件

  • 在main.js进行全局注册

import HelloWorld from '@/components/HelloWorld.vue'
/* 
  全局注册的语法
  Vue.comoponent(参数1,参数2)
  参数1:组件的名称,这个名称可以在其他组件中直接进行调用
  参数2:导入的组件对象名称
*/
Vue.component('HelloWorld',HelloWorld)
  • 在相应的组件中直接引入

<HelloWorld></HelloWorld>

5、父子组件

  • 定义子组件MovieItem

<template>
    <div class="container-item">
        <div class="item-1">
            <img src="https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2455050536.jpg" alt="">
        </div>
        <div class="item-2">
            <div>大话西游之大圣娶亲 西遊記大結局之仙履奇緣</div>
            <div></div>
        </div>
    </div>
</template>
​
<script>
export default {
​
}
</script>
​
<style lang="scss">
    .container-item{
        display: flex;
        flex-direction: column;
        width: 135px;
        height: 220px;
        border: 1px solid #000;
        border-radius: 15px;
        margin: 5px;
        .item-1{
            height: 177px;
            background-color: blue;
            overflow: hidden;
            img{
                width: 135px;
            }
        }
        .item-2{
            display: flex;
            flex-grow: 1;
            background-color: red;
        }
    }
</style>
  • 定义MovieList组件

<template>
   <div class="container">
        <div class="title-container"></div>
        <div class="content-container">
            <movie-item></movie-item>
            <movie-item></movie-item>
            <movie-item></movie-item>
            <movie-item></movie-item>
            <movie-item></movie-item>
            <movie-item></movie-item>
            <movie-item></movie-item>
            <movie-item></movie-item>
        </div>
   </div>
</template>
​
<script>
import MovieItem from './MovieItem.vue'
export default {
    components:{
        MovieItem
    }
}
</script>
​
<style lang="scss">
    .container{
        display: flex;
        width: 617px;
        height: 500px;
        flex-direction: column;
        background-color: yellow;
        .title-container{
            display: flex;
            width: 100%;
            height: 40px;
            background-color: red;
        }
        .content-container{
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            width: 100%;
            flex-grow: 1;
            background: springgreen;
        }
    }
</style>

如上操作电影的列表项内容、图片、评分都是固定的,如果想要内容、图片、评分不一样,就应该学习组件的通信

二、组件通信

组件的通信方式很多,大致分成如下几种

  • 父向子传值的方式:props

  • 子组件向父组件通信:自定义事件$emit

  • 兄弟组件的通信:

    • 状态提升

    • EventBus

    • 订阅与

    • 发布模式

  • 跨级组件之间的通信:provider和inject

  • 无关系组件之间通信:状态机(vuex,pinia)

1、父组件向子组件通信

一个组件的数据来自两个地方,一个地方是来自本组件内部(data),另一个来自组件外部(props),props用来接收该组件之外的数据(来自它的父组件)

1.1、父组件向子组件通信的步骤
  • 首先在子组件中声明props选项,然后定义要传递的数据名称

export default {
    props:['title','imgurl']
}
  • 其次在子组件的template部分,使用v-bind动态的接收属性,使用插值表达式动态的接收内容

<template>
    <div class="childBox">
        <h2>我是儿子</h2>
        <div>
            <div>{{title}}</div>
            <div>
                <img :src="imgurl">
            </div>
        </div>
    </div>
</template>
  • 在父组件的template引入子组件的标签部分进行传值

<template>
  <div class="parentBox">
    <h1>我是父组件</h1>
    <child :title="title" :imgurl="imgurl"></child>
  </div>
</template>

<script>
import Child from './components/Child.vue'
export default {
  components: { Child },
  data(){
    return{
      title:'哈利·波特与魔法石 Harry Potter and the Sorcerer',
      imgurl:'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2614949805.jpg'
    }
  }
}
</script>

<style>
  .parentBox{
    width: 300px;
    height: 500px;
    background-color:tomato;
  }
</style>
1.2、props的验证器和默认值

子组件通过props来引入外部的数据,但是这是这些数据的类型和内容如果要加以限制,就需要使用都props的验证器

1)验证类型

Prop 的验证是指子组件可以对外部传递进来的数据的类型或内容设置验证规则。例如在子组件组中设置想要接收age数据的值是Number类型,如果接收到的不是Number类型,浏览器中就会抛出报错。

如果要设置验证,props属性的值需要切换为对象:

export default {
      props: {
          name:String
    }
}
2)其他验证规则

除了定义简单的数据类型验证外,props 还支持其他的一些验证规则:

1)设置多个类型,例如 age 属性接收数字和字符串都可以:

export default {
      props: {
          age: [Number, String]
    }
}

2)必填属性,例如 age 属性必须传值:

export default {
      props: {
        age: {
            type: [Number, String],
            required: true
        }
    }
}

3)默认值,例如 age 属性如果没有传值,就使用默认值 18

export default {
      props: {
        age: {
            type: [Number, String],
            default: 18
        }
    }
}

4)对象和数组类型的默认值,必须通过函数的返回值来设置:

export default {
      props: {
        friends: {
            type: Array,
            default: () => ['韩梅梅', '李华'], // 数组的默认值
            // 或
            type: Object,
            default: () => ({ name: '韩梅梅' })  // 对象的默认值
        }
    }
}

5)自定义验证规则,例如 age 接收的值必须在 18 到 25 的范围内:

export default {
      props: {
        age: {
            type: Number,
            validator: value => value >= 18 && value <= 25
        }
    }
}

注意:Prop 会在一个组件创建之前进行验证,所以组件的属性 (如datacomputed等) 在defaultvalidator函数中是不可用的。

2、子组件向父组件传值

子组件向父组件传值是一种逆向行为,通过$emit自定义事件的方式来进行传值,具体的步骤如下

  • 子组件中触发相应事件,通过$emit来自定义事件

<div>{{cmsg}}</div>
<button @click="sendMsgToParent">发送到父组件</button>

methods:{
        sendMsgToParent(){
          //在这里调用vue中的$emit方法,完成自定义事件设置
         /* 
            $emit方法用来自定义事件
            它有两个参数
            参数1:自定义事件的名称
            参数2:所要传递的数据
         */
          this.$emit('make',this.cmsg)
        }
  }
  • 在父组件引用子组件的开始标签中调用这个自定义事件

 <child @make="getMsgFromChild"></child>
  • 在父组件的methods选项中定义方法用来实现父组件接收子组件的方法

methods:{
    //此处用于接收子函数的参数是$emit的第2个参数
    getMsgFromChild(val){
       console.log(val)
    }
}
  • 将从子组件中接收的信息赋值给该组件的data选项中的数据

<div>{{ info }}</div>

data(){
    return{
      info:''
    }
  },
  methods:{
    //此处用于接收子函数的参数是$emit的第2个参数
    getMsgFromChild(val){
       this.info=val
    }
}
  • 通过父子传值删除电影项

    methods:{
        getId(id){
            this.movie=this.movie.filter(item=>item.id!=id)
        }
    }

3、兄弟组件的通信

兄弟组件之间的通信可以采用三种方式

  • 状态提升:首先把组件的数据通过子传父的方式传递给父组件,而后再将父组件接收到这个数据通过父传子的方式传递给另外兄弟组件

  • 事件总线:

  • 发布与订阅

1)通过eventBus进行兄弟组件传值
  • 在src/utils文件夹下创建eventBus.js

//导入vue依赖包
import Vue from 'vue'
//实例化一个Vue对象并默认导出
export default new Vue()
  • 在数据的发送方编写代码如下

import bus from '@/utils/eventBus'
export default {
    data(){
        return{
            msg:''
        }
    },
    methods:{
        sendMsgToBrother(){
           //调用vue实例中的$emit来完成发送信息
           bus.$emit('sharekey',this.msg)
        }
    }
}

说明:调用bus对象的$emit方法来完成发送信息

  • 在数据的接收方,可以使用bus.$on方法来接收信息

import bus from '@/utils/eventBus'
export default {
    data(){
        return{
            fromBrotherMsg:''
        }
    },
    //调用组件创建完之后会被调用
    created(){
       bus.$on('sharekey',val=>{
        this.fromBrotherMsg=val
       })
    }
}

特别注意:我们在使用bus.$on接收信息的时候,它的第2个参数应该写成箭头函数(这里由于this指向的问题)

2) 发布与订阅方式
  • 在终端上通过npm下载pubsub-js包

npm i pubsub-js
  • 在信息发送方,通过pubsub对象中的publish方法来实现发送

import pubsub from 'pubsub-js'
export default {
    data(){
        return{
            msg:''
        }
    },
    methods:{
        sendMsgToBrother(){
          pubsub.publish('gileskey',this.msg)
        }
    }
}
  • 在信息的接收方,使用pubsub.subscribe方法来接收信息

import pubsub from 'pubsub-js'
export default {
    data(){
        return{
            fromBrotherMsg:''
        }
    },
    created(){
       pubsub.subscribe('gileskey',(arg1,arg2)=>{
           //arg1= 'gileskey'
           //arg2= this.fromBrotherMsg
          this.fromBrotherMsg=arg2
       })
    }
}

4、跨级组件的传值

如果要进行跨级组件的通讯,可以考虑使用provider/inject选项来完成

App.vue组件

<template>
    <div class="box">
      <h1>祖父组件</h1>
      <child></child>
    </div>
</template>

<script>
import Child from '@/components/Child.vue'
export default {
  components:{
    Child
  },
  provide:{
    akey:'我是爷爷'
  }
}
Child.vue组件

<template>
    <div class="cbox">
        <h2>子组件</h2>
       <grand-son></grand-son>
    </div>
</template>

<script>
import GrandSon from '@/components/GrandSon.vue'
export default {
    components:{
        GrandSon
    }
}
</script>

<style>
    .cbox{
        width: 400px;
        height: 300px;
        background-color: springgreen;
    }
</style>
GrandSon.vue组件

<template>
    <div class="gcbox">
        <h3>孙子组件</h3>
        <div>{{akey}}</div>
        <grand-son-son></grand-son-son>
    </div>
</template>

<script>
import GrandSonSon from '@/components/GrandSonSon.vue'
export default {
    components:{
        GrandSonSon
    },
    inject:['akey']
}
</script>

<style>
    .gcbox{
        width: 300px;
        height: 200px;
        background-color: yellow;
    }
</style>

三、插槽

slot的官方定义是用于组件内容分发,简单通俗的解释就是在组件化开发中,虽然组件是一样的,但是在不同的使用场景,组件的某一部分需要有不同的内容显示。slot就好比组件开发时定义的一个参数,如果不传入值就当默认值使用,如果传入了新值,在组件调用时就会替换定义时的slot默认值。

slot分为三大类:

  • 匿名slot

  • 具名slot

  • 作用域插槽

1、匿名插槽

匿名插槽是没有名字的插槽,称为匿名插槽

案例:编写一个模态框组件

<template>
    <div class="box">
        <div class="header">
            <div class="close">&times;</div>
        </div>
        <div class="main">
            <slot>暂无内容</slot>
        </div>
    </div>
</template>

<script>
export default {

}
</script>

<style lang="scss">
    .box{
        width: 325px;
        border-radius: 5px;
        border: 1px solid #000;
        .header{
            position: relative;
            height: 40px;
            background-color: #007CB7;
            .close{
                position:absolute;
                right: 10px;
                line-height: 40px;
                color: white;
                font-size: 32px;
            }
        }
        .main{
            padding: 10px;
            text-align: center;
        }
    }
</style>

在页面组件调用的时候

<template>
    <div>
        <ModalDialog title="登录">
            <div>
              <div class="item">
                 <input type="text" placeholder="请输入手机号" class="input">
              </div>
              <div class="item">
                 <input type="text" placeholder="请输入密码" class="input">
              </div>
              <div class="item">
                  <button class="loginBtn">登录</button>
              </div>
            </div>
        </ModalDialog>

        <modal-dialog title="个人介绍">
            <img class="headImg" src="https://img0.baidu.com/it/u=3464224756,2566048582&fm=253&fmt=auto&app=138&f=JPEG?w=350&h=500" alt="">
        </modal-dialog>
    </div>
</template>

<script>
import ModalDialog from '@/components/ModalDialog.vue'
export default {
  components:{
    ModalDialog
  }
}
</script>

<style>
  .loginBtn{
    width: 250px;
    height: 37px;
    background-color:#007CB7;
    border: none;
    border-radius: 5px;
    text-align: center;
    line-height: 37px;
    color: white;
  }
  .item{
    line-height: 50px;
  }
  .input{
    width: 250px;
    height: 35px;
    border-radius: 5px;
  }
  .headImg{
    width: 300px;
  }
</style>

2、具名插槽

  • 编写自定义组件使用<slot>完成插槽的占位,由于有多个插槽,所以一定要在每个<slot>上添加name属性,使用name属性来为该插槽取名字

<template>
   <div class="box">
      <div>
        <slot name="title">暂无标题</slot>
      </div>
      <div>
        <slot name="name">暂无名称</slot>
      </div>
      <div>
         <slot name="multipart">
            <img src="http://old.woniuxy.com/page/img/head_picture/0.jpg" style="width:30px;height:30px" alt="">
        </slot>
      </div>
      <div>
        <slot name="desc">暂无简介</slot>
      </div>
   </div>
</template>
  • 页面组件中要引用组件,并且给相应插槽赋值,有如下规则

    • 必须使用<template>

    • 使用v-slot:插槽名称或者使用#插槽名称可以在调用组件的时候将内容传递给组件的内容slot占位部分

<template>
  <div class="container">
    <card>
       <template v-slot:title>风华</template>
       <template v-slot:name>天真</template>
       <template v-slot:multipart>
          <img style="width:30px" src="http://old.woniuxy.com/page/image/userIcon/teacherIcon/mayuhang.jpg">
       </template>
       <template v-slot:desc>
          6年项目研发经验及管理经验,PMP证书持有者
       </template>
    </card>
    <card>
       <template #title>学苑</template>
       <template #name>海东</template>
    </card>
  </div>
</template>

3、作用域插槽

所谓的作用域插槽是带数据插槽,将子组件的数据传递给父组件,然后父组件得到这个数据后展示不同的效果,我们将这种称为作用域插槽

<template>
   <div class="cbox">
        <div class="header">
            <span>{{title}}</span>
        </div>
        <div class="main">
            <ul>
                <li v-for="(item,index) in items" :key="index">
                   <slot :item="item">{{item.name}}</slot>
                </li>
            </ul>
        </div>
   </div>
</template>

<script>
export default {
    props:['title','items']
}
</script>

<style lang="scss">
    .cbox{
        display: flex;
        flex-direction: column;
        width: 215px;
        height: 300px;
        border: 1px solid #ccc;
        border-radius: 5px;
        .header{
            display: flex;
            align-items: center;
            margin-left: 5px;
            font-size: 18px;
            font-weight: bold;
            height: 35px;
            border-bottom: 1px dashed #ccc;
        }
        li{
            line-height: 32px;
        }
        .main{
            flex-grow: 1;
        }
    }
</style>

App.vue

<template>
    <div style="display:flex">
       <MyList title="Shape" :items="shapes"></MyList>
       <MyList title="Color" :items="colors">
          <template slot-scope="scope">
            <div class="item">
               <div class="bock" :style="`background:${scope.item.hex}`"></div>
               <div>{{scope.item.name}}</div>
            </div>
          </template> 
       </MyList>
    </div>
</template>

<script>
import MyList from '@/components/MyList.vue'
export default {
  components: { MyList},
  data(){
    return{
      shapes: [
        { name: "Square", sides: 4 },
        { name: "Hexagon", sides: 6 },
        { name: "Triangle", sides: 3 },
      ],
      colors: [
        { name: "Yellow", hex: "#F4D03F" },
        { name: "Green", hex: "#229954" },
        { name: "Purple", hex: "#9B59B6" },
      ]
    }
  }
}
</script>

<style>
  .item{
    display: flex;
  }
  .bock{
    width: 40px;
    height: 20px;
    border: 1px solid #000;
  }
</style>

四、组件的生命周期【面试题重点】

1、什么是生命周期

所谓的生命周期是指该组件对象从开始创建到销毁回收的整个全过程

2、生命周期函数

在生命周期中被自定执行的函数我们称为生命周期函数,也称为钩子函数

3、vue2中生命周期的函数

整个组件从开始到销毁要经过生命周期的阶段,每到一个阶段,相对应的函数就会被执行

生命周期含义
beforeCreate在组件创建之前被调用
created在组件创建之后被调用
beforeMount模板编译、挂载之前被调用
mounted模板编译、挂载之后被调用
beforeUpdate组件更新之前被调用
updated组件更新之后被调用
beforeDestory在组件销毁之前被调用
destoryed在组件销毁之后被调用

4、生命周期的阶段

我们将这个生命周期的阶段划分为三个阶段

5、生命周期图示【理解】

第1个阶段:组件创建阶段

  • new Vue():创建组件的实例对象

  • Init Events&Lifecycle:初始化事件和生命周期函数

  • beforeCreate:组件中的props/data/methods这些尚未创建,都处于不可以用的状态,在实际的开发过程中几乎没有用处

  • Init injections & reactivity:组件props/data/methods才开始初始化这些选项

  • created:组件中的props/data/methods这些数据已经初始化成功了,但是这里不能放问页面的DOM元素,因为此时模板还没有被编译创建出来

   beforeCreate(){
     console.group('----1、beforeCreate--------');
     console.log('data',this.num);  //undefined
     console.log('methods',this.fn); //undefined
     console.log('props',this.ptitle);//undefined
     console.groupEnd()
   },
  created(){
    console.group('----2、created--------');
    console.log('data',this.num);//可以访问数据为0
    console.log('methods',this.fn);  //也可以访问
    console.log('props',this.ptitle); //也可以访问
    console.log('dom元素', this.$refs.titleDom); //不能访问,这里的数据为undefined,因为模板没有创建
    console.groupEnd()
  },

总结:在实际开发过程中beforeCreate几乎不用,created使用的比较多,一边情况在这里完成网络请求,和后端交互、完成一些初始化的操作,创建定时器等功能更

向后端发送网络请求的技术有三种

  • Ajax方式:这种方式存在弊端就是

    <1>.AJAX干掉了Back和History功能,即对浏览器机制的破坏。 在动态更新页面的情况下,用户无法回到前一个页面状态,因为浏览器仅能记忆历史记录中的静态页面。一个被完整读入的页面与一个已经被动态修改过的页面之间的差别非常微妙;用户通常会希望单击后退按钮能够取消他们的前一次操作,但是在Ajax应用程序中,这将无法实现。

    <2>.AJAX的安全问题。 AJAX技术给用户带来很好的用户体验的同时也对IT企业带来了新的安全威胁,Ajax技术就如同对企业数据建立了一个直接通道。这使得开发者在不经意间会暴露比以前更多的数据和服务器逻辑。Ajax的逻辑可以对客户端的安全扫描技术隐藏起来,允许黑客从远端服务器上建立新的攻击。还有Ajax也难以避免一些已知的安全弱点,诸如跨站点脚步攻击、SQL注入攻击和基于Credentials的安全漏洞等等。

    <3>.对搜索引擎支持较弱。 对搜索引擎的支持比较弱。如果使用不当,AJAX会增大网络数据的流量,从而降低整个系统的性能。

    <4>.破坏程序的异常处理机制。 至少从目前看来,像Ajax.dll,Ajaxpro.dll这些Ajax框架是会破坏程序的异常机制的。关于这个问题,曾在开发过程中遇到过,但是查了一下网上几乎没有相关的介绍。后来做了一次试验,分别采用Ajax和传统的form提交的模式来删除一条数据……给我们的调试带来了很大的困难。

    <5>.违背URL和资源定位的初衷。 例如,我给你一个URL地址,如果采用了Ajax技术,也许你在该URL地址下面看到的和我在这个URL地址下看到的内容是不同的。这个和资源定位的初衷是相背离的。

    <6>.AJAX不能很好支持移动设备。 一些手持设备(如手机、PDA等)现在还不能很好的支持Ajax,比如说我们在手机的浏览器上打开采用Ajax技术的网站时,它目前是不支持的。

    <7>.客户端过肥,太多客户端代码造成开发上的成本。

  • fetch方式:这种实际上对Ajax的封装,比Ajax要强

  • axios方式:目前使用的最多的一种

案例1:使用原生ajax获取网络数据

步骤如下

第1步:在src/utils目录下创建request.js文件,该文件用于封装ajax请求

//使用具名导出ajax函数
export function ajax(method,url){
  return new Promise((resolve,reject)=>{
     //创建XMLHttpRequest对象
     let xhr=new XMLHttpRequest()
     //初始化XMLHttpRequest对象
     xhr.open(method,url,true)//true表示异步请求
     //如果是GET请求发送信息
     xhr.send()
     //设置回调函数
     xhr.onreadystatechange=function(){
        //判断状态码必须是4的时候并且响应码必须是200的时候返回数据
        if(xhr.readyState==4){
            if(xhr.status==200){
              //获取服务端发送回来的数据
              resolve(xhr.responseText)
            }else{
              reject('network failure')
            }
        }
     }
  })
}

第2步:在组件中引入的created函数中调用获取网络数据

import {ajax} from '@/utils/request'
export default {
    data(){
        return{
            list:[]
        }
    },
    methods:{
       async getOperas(){
            //使用async/await
            let response=await ajax('GET','https://www.fastmock.site/mock/4441a79ad5f884f83b784cf4c588bdb6/movies/getAllOperas')
            this.list=JSON.parse(response).operas;
        }
    },
     created(){
       //使用then方式获取promies成功后的数据
    //    ajax('GET','https://www.fastmock.site/mock/4441a79ad5f884f83b784cf4c588bdb6/movies/getAllOperas').then(response=>{
    //        //将返回回来的数据由JSON转成js对象
    //        let result=JSON.parse(response)
    //        console.log(result.operas);
    //        //将获取的数据赋值给data的list数据
    //        this.list=result.operas
    //    })
        this.getOperas()
    }
}

第3步:在template模板中渲染

<template>
    <div>
        <h1>获取所有的电影院信息</h1>
        <ul> 
            <li v-for="item in list" :key="item.id">{{item.name}}</li>
        </ul>
    </div>
</template>
第2个阶段:编译HTML模板并渲染到浏览器中

  • 这个过程的主要工作可以理解为将data中数据读到内存中,再填充到template之后进行编译,这个编译过程由vue-template-compiler这个依赖包来完成编译的

  • beforeMount:将内存中编译好的HTML结构然后渲染到浏览器中,此时浏览器还没有中还没有当前DOM结构,在这钩子函数中直接操作DOM

  • create vm.$el and replace "el" with it:用内存中编译好的HTML结构,替换掉el属性指定的DOM元素

  • mounted:已经把内存中的HTML结构成功的渲染到了浏览器之中,此时你可以直接在这个钩子函数中去操作DOM元素了

第3阶段:组件更新阶段

  • 当数据变化变化的时就会触发beforeUpdate,这个时候data数据是会变化的,但是页面还没有渲染

  • Virtual DOM re-render and patch:根据最新的数据,重新渲染组件的DOM结构

  • updated:已经是最新的数据,完成了组件DOM结构的重新渲染

第4阶段:组件销毁阶段

beforeDestory:这个生命周期函数,是组件即将销毁,此时尚未销毁组件,组件还能正常运行,一般在这个函数会完成资源的释放操作

Teardown watcher... 销毁当前组件的侦听器、子组件、事件监听

destoryed:组件已经被销毁,此组件在浏览器中的DOM已经被完全移除

案例:停止定时器操作

 created(){
    //定义一个间隔定时器,每隔1秒钟进行加1操作
    this.times=setInterval(() => {
      console.log('num',this.num);
      this.increment()
    }, 1000);
 }
 beforeDestroy(){
    console.log('---7、beforeDestroy-------------');
    //调用销毁定时器的方法
    clearInterval(this.times)
  },

五、动态组件【了解】

1、概念

动态组件是指动态的切换组件的

2、语法

<component :is="加载的组件名称"></component>

3、keep-alive

默认情况下,切换动态组件的时,无法保存组件的状态的,此时可以使用使用keep-alive来实现缓存组件中的状态,从而保存切换时组件状态的

使用动态组件的时候当切换到Second组件的时候,首先先执行beforeCreate、created、beforeMount之后会把First组件进行销毁会调用First组件的beforeDestory和destoryed方法,所以第一个组件的01状态就不会被保存

<template>
   <div>
      <button @click="cardName='card'">aa</button>
      <button @click="cardName='zuoyongyuF'">bb</button>
   <keep-alive>
      <component :is="cardName"></component>
   </keep-alive>
   </div>
</template>
<script>

import card from './views/card.vue';
import zuoyongyuF from '@/views/zuoyongyuF.vue'

export default {
   components:{card,zuoyongyuF},
   data(){
      return{
         cardName:''
      }
   }
}
</script>

<style lang="scss">
</style>

4、keep-alive的相关的生命周期

在vue2的生命周期中有8个常用方法,但是如果使用了keep-alive后,还有两个相关的生命周期的钩子函数

  • deactivated:当组件被缓存的时候,会调用该生命周期的函数

  • activated:当组件被激活的时候,会自动触发组件的该函数

注意:当进入到第2个组件的时候,首先执行beforeCreate、created、beforeMount,此时将第一个组件的数据缓存起来,然后在调用第2个组件的mounted函数和activated函数,后续再次切换的时候就只会执行和keep-alive相关的的激活和缓存方法。

5、include和exclude属性

如果在动态组件的外面使用keep-alive将动态组件包起来,那么动态组件引入的组件都会被缓存,要么不使用keep-alive包裹就不会缓存任何数据,在实际开发中到底是缓存数据好还是不缓存数据好。

如果在一个动态组件中,需要缓某个组件可以使用include属性,将需要缓存的组件写入,如果需要缓存多个,之间使用逗号(,)隔开

 <keep-alive include="First,Third">
      <component :is="componentName"></component>
 </keep-alive>

如果在一个动态组件中,不需要缓某个组件可以使用exclude属性,将不需要缓存的组件写入,如果不需要缓存多个,之间使用逗号(,)隔开

 <keep-alive exclude="Third,First">
      <component :is="componentName"></component>
    </keep-alive>

六、异步组件

1、为什么使用异步组件

之前如果要使用一个组件必须要先使用import XX from '组件路径'的方式导入组件,然后通过components中注册这个组件,但是这种导入导入组件的方式相当于页面一加载,将所有的组件全部导入,然后再注册,这样对于性能来讲负担很重,那么如何能解决这个问题,可以使用import()或者require函数的方式导入组件,再使用的时候才导入它,这样性能就有一个大幅度的提升

2、异步组件的好处

可以避免页面一加载时就去加载全部的组件,从而导致页面访问时间变长的问题,使用异步组件后,只有当需要某个组件的时候才会去加载需要的组件。

<template>
   <div>
        <h1>异步组件的演示案例</h1>
        <button @click="handleclick">按钮</button>
        <div v-if="show">
            <AsyncList></AsyncList>
        </div>
   </div>
</template>

<script>
import LoadingComponent from '@/components/LoadingComponent.vue'
import ErrorComponent from '@/components/ErrorComponent.vue'
//定义了一个关于异步组件的对象
const AsyncList=()=>{
    return{
      //component:要加载的组件,组件使用异步方式加载
      component:import('@/components/MyList.vue'),
      //加载中显示的组件
      loading:LoadingComponent,
      //在指定的毫秒数内没有加载进来则进入该组件
      error:ErrorComponent,
      //延时毫秒数
      delay:200,
      //超时时间毫秒数
      timeout:21500,
    }
}
export default {
    components:{
       AsyncList
    },
    data(){
        return{
            show:false
        }
    },
    methods:{
        handleclick(){
            this.show=!this.show
        }
    } 
}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/931709.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot的日志级别你了解吗(自定义打印日志)?

1 SpringBoot日志介绍 ⽇志是程序的重要组成部分&#xff0c;想象⼀下&#xff0c;如果程序报错了&#xff0c;不让你打开控制台看⽇志&#xff0c;那么你能找到报错的原因吗&#xff1f; 如果是简单的错误有可能找出来&#xff0c;但是对于开发中的大多数错误还是需要我们打开…

el-backtop返回顶部的使用

2023.8.26今天我学习了如何使用el-backtop组件进行返回页面顶部的效果&#xff0c;效果如&#xff1a; <el-backtop class"el-backtop"style"right: 20px; bottom: 150px;"><i class"el-icon-caret-top"></i></el-backtop&…

WebGL 绘制函数gl.drawArrays

gl.drawArrays&#xff08;&#xff09;的第1个参数 WebGL方法gl.drawArrays&#xff08;&#xff09;既强大又灵活&#xff0c;通过给第1个参数mode指定不同的值&#xff0c;在这个参数上指定不同的值&#xff0c;我们可以按照不同的规则绘制图形。 下图中的7种基本图形是We…

Java项目-苍穹外卖-Day05-Redis技术应用

1.店铺营业状态设置 需求分析和设计 左上角要求是有回显的 所以至少两个接口 1.查询营业状态接口&#xff08;分为了管理端和用户端&#xff09; 2.修改营业状态接口 因为管理端和用户端路径不同&#xff0c;所以现在是至少三个接口的 可以发现如果存到表里除了id只有一个…

【Day-20慢就是快】代码随想录-栈与队列-删除字符串中的所有相邻重复项

给出由小写字母组成的字符串 S&#xff0c;重复项删除操作会选择两个相邻且相同的字母&#xff0c;并删除它们。 在 S 上反复执行重复项删除操作&#xff0c;直到无法继续删除。 在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。 例&#xff1a; 输入&#xff…

Linux学习(三)----文件打开及创建

1 demo1.c的建立 首先打开终端输入 touch file1 接着输入&#xff1a; vi demo1.c 接着重新打开一个终端&#xff0c;输入&#xff1a; man 2 open 2 demo1.c内容编辑 2.1 复制头文件 2.2 程序基础框架 #include <sys/types.h> #include <sys/stat.h>#include &l…

同态比较算法

参考文献&#xff1a; [PS73] Paterson M S, Stockmeyer L J. On the number of nonscalar multiplications necessary to evaluate polynomials[J]. SIAM Journal on Computing, 1973, 2(1): 60-66.[IZ21] Iliashenko I, Zucca V. Faster homomorphic comparison operations …

基于蛾群算法优化的BP神经网络(预测应用) - 附代码

基于蛾群算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于蛾群算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.蛾群优化BP神经网络2.1 BP神经网络参数设置2.2 蛾群算法应用 4.测试结果&#xff1a;5.Matlab代码 摘要…

cpolar做一个内网穿透

因为不在公司&#xff0c;需要访问公司的数据库&#xff0c;所以做一个内网穿透 下载安装 下载地址&#xff1a; https://dashboard.cpolar.com/get-started 下载后是个压缩包&#xff0c;解压后傻瓜式安装 操作隧道 安装后打开Cpolar Web UI 登录账号&#xff0c;查看隧…

python面试题--1

目录 python面试题 1&#xff09;什么是Python&#xff1f;使用Python有什么好处&#xff1f; 2&#xff09;什么是PEP 8&#xff1f; 3&#xff09;什么是序列化和非序列化&#xff1f; 4&#xff09;如何解释Python&#xff1f; 5&#xff09;如何在Python中内存管理&a…

Unity3D软件安装包分享

目录 一、软件简介 二、软件下载 一、软件简介 Unity3D是一款全球知名的游戏开发引擎&#xff0c;由Unity Technologies公司开发。它提供了一个跨平台、多功能的开发环境&#xff0c;支持创建2D和3D游戏、交互式应用、虚拟现实、增强现实等多种类型的应用程序。以下是Unity3D…

山西电力市场日前价格预测【2023-08-27】

日前价格预测 预测明日&#xff08;2023-08-27&#xff09;山西电力市场全天平均日前电价为318.11元/MWh。其中&#xff0c;最高日前电价为356.66元/MWh&#xff0c;预计出现在19: 15。最低日前电价为273.48元/MWh&#xff0c;预计出现在04: 30。 价差方向预测 1&#xff1a; 实…

01-Flask-简介及环境准备

Flask-简介及环境准备 前言简介特点Flask 与 Django 的比较环境准备 前言 本篇来介绍下Python的web框架–Flask。 简介 Flask 是一个轻量级的 Web 框架&#xff0c;使用 Python 语言编写&#xff0c;较其他同类型框架更为灵活、轻便且容易上手&#xff0c;小型团队在短时间内…

785. 判断二分图

785. 判断二分图 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 785. 判断二分图 https://leetcode.cn/problems/is-graph-bipartite/description/ 完成情况&#xff1a; 解题思路&#xff1a; 题目解释&#x…

清洁能源使用的社会发展意义

应用清洁能源是转变经济增加途径的有效手段&#xff0c;能够在减少污染物、降低企业经营成本的同时&#xff0c;提高企业经济效益和社会经济效益。 应用清洁能源是保护环境的最佳方式和必然选择&#xff0c;改变末端治理的现状&#xff0c;采取以预防为主的环境保护与发展理…

opencv/C++ 人脸检测

前言 本文使用的测试资源说明&#xff1a; opencv版本&#xff1a;opencv 4.6.0 人脸检测算法 Haar特征分类器 Haar特征分类器是一个XML文件&#xff0c;描述了人体各个部位的Haar特征值。包括&#xff1a;人脸、眼睛、鼻子、嘴等。 opencv 4.6.0自带的Haar特征分类器&…

护目镜佩戴检测识别算法

护目镜佩戴检测识别算法通过opencvpython网络深度学习模型&#xff0c;护目镜佩戴检测识别算法实时监测工人的护目镜佩戴情况&#xff0c;发现未佩戴或错误佩戴的情况&#xff0c;及时提醒调整。与C / C等语言相比&#xff0c;Python速度较慢。也就是说&#xff0c;Python可以使…

pyqt5-问答框

choice QMessageBox.question(self, Change Text?, Would you like to change the button text?,QMessageBox.Yes | QMessageBox.No, QMessageBox.No) 分别对应 1 父组件 2 问答框标题 3 问答框文字 4 问答框展示的按钮 5 问答框的默认按钮选择

Scikit-Learn 和深度学习怎么选择

大家好&#xff0c;今天我们要聊聊一个机器学习的话题&#xff1a;Scikit-Learn 和深度学习&#xff0c;到底哪一个更适合解决你的问题&#xff1f;我们先来看看这两种技术的异同点&#xff0c;然后再讲讲如何在实际问题中做出选择。 1. Scikit-Learn 与深度学习&#xff1a;谁…

JavaWeb优雅实现接口参数校验

目录 1 背景2 如何优雅地校验参数2.1 官方指导意见2.2 注解用法说明 3 ControllerAdvice同时配置过滤多个包3.1 springboot 多个RestControllerAdvice时的拦截顺序3.2 解决方法 1 背景 要对方法的参数进行校验&#xff0c;最简单暴力的写法是这个样子&#xff1a; public stati…