Vue 进阶语法-下篇

【15】声明周期钩子

(1)简单介绍组件

  • 在Vue中,组件是可复用的Vue实例,拥有与Vue实例相似的选项,例如datacomputedwatchmethods以及生命周期钩子等。
  • 组件是构建大型应用的基础。通过使用组件,我们可以将UI拆分为独立、可复用的部分,并使整个应用更容易管理和维护。

image-20240426213048853

  • template: 定义组件的HTML模板。
  • data: 返回一个对象,表示组件的初始状态。在这里,组件有一个title属性,其初始值为'首页'
  • methods: 定义组件的方法。handleClick方法会在按钮被点击时调用,并弹出一个警告框显示title的值。

(2)vue2生命周期钩子

  • 创建阶段

    • beforeCreate:在实例初始化之后,数据观测(data observer) 和事件/监听器配置之前被调用。在这个阶段,Vue实例的属性和方法尚未初始化, 此时template和data属性都为空。
    • created:在实例创建完成后被立即调用。在这个阶段,Vue实例已经初始化,可以访问到datapropsmethodscomputed等属性,此时data属性有值,但是template属性没有值。
    • image-20240427150641469
  • 挂载阶段

    • beforeMount:在挂载开始之前被调用。 在这个阶段,模板编译已完成,但尚未将组件挂载到DOM中,此时template属性为空。
    • mounted:在实例被挂载到DOM上后调用。在这个阶段,组件已经被挂载到DOM中,可以操作DOM元素。
    • image-20240427151023671
  • 更新阶段

    • beforeUpdate:在数据改变后,DOM更新之前被调用。在这个阶段,组件的数据已经被修改,但DOM尚未更新
    • updated:在DOM更新完成后被调用。在这个阶段,组件的数据已经更新,并且DOM也已经重新渲染。
    • image-20240427151339596
  • 销毁阶段

    • beforeDestroy:在实例销毁之前调用。在这个阶段,实例仍然可以访问datapropsmethodscomputed等属性,但已经无法访问到DOM元素。
    • destroyed:在Vue实例销毁后被调用。在这个阶段,Vue实例已经被销毁,所有的事件监听和子组件也都已经被移除。
    • image-20240427151916469
<body>
<div id="app">
    <Header1 v-if="isShow"></Header1>
    <button @click="handleClick">销毁或加载</button>
</div>
</body>

<script>
    Vue.component('Header1', {
        template: `
          <div>
            <button @click="handleClick">{{ info }}</button>
          </div>`,
        data() {
            return {
                info: '后台管理'
            }
        },
        methods: {
            handleClick() {
                this.info = '前台管理'
            }
        },
        beforeDestroy() {
            console.log("销毁之前")
        },
        destroyed() {
            console.log("销毁以后")

        },

        // beforeUpdate() {
        //     console.log("挂载之前")
        // },
        // updated() {
        //     console.log("挂载以后")
        // },
        // beforeMount() {
        //     console.log("挂载之前")
        //     console.log(this.$el)
        // },
        // mounted() {
        //     console.log("挂载以后")
        //     console.log(this.$el)
        // }
        // beforeCreate() {
        //     console.log("创建之前")
        //     console.log(this.info)
        //     console.log(this.$el)
        // },
        // created() {
        //     console.log("创建以后")
        //     console.log(this.info)
        //     console.log(this.$el)
        // }

    });

    var vm = new Vue({
        el: "#app",
        data: {
            isShow: true
        },
        methods: {
            handleClick() {
                this.isShow = !this.isShow
            }
        }
    })
</script>

(3)使用案例

  • 子组件在多种场景中可能需要使用定时器,例如定期获取数据或执行某个周期性任务。在这种情况下,正确管理定时器至关重要,以避免资源泄漏和不必要的性能开销。
  • 在Vue中,我们可以利用生命周期钩子来实现定时器的创建和销毁。具体来说,当子组件创建时(created钩子),我们可以启动定时器;而当子组件销毁时(beforeDestroy钩子),我们则需要清除定时器。

image-20240427153647964

<body>
<div id="app">
    <Child v-if="isShow"></Child>
    <button @click="handleClick">销毁或加载</button>
</div>
</body>

<script>
    Vue.component('Child', {
        template: `
          <div>
            <h2 v-text="info"></h2>
          </div>`,
        data() {
            return {
                info: '后台管理',
                t: null,
            }
        },
        methods: {
            autoAdd() {
                this.info = this.info + '.'
                console.log(this.info)
            }
        },
        beforeDestroy() {
            clearInterval(this.t)
            t = null

        },
        created() {
            this.t = setInterval(this.autoAdd, 1000)
        },
    });

    var vm = new Vue({
        el: "#app",
        data: {
            isShow: true
        },
        methods: {
            handleClick() {
                this.isShow = !this.isShow
            }
        }
    })
</script>

【16】组件使用

(1)组件的分类

  • 全局组件

    • 全局组件是在应用的根组件中注册,因此可以在整个应用的任何组件中使用的组件。
    • 它们具有全局可用性,意味着无需在每个组件中单独引入或注册,就可以直接在需要的地方使用。
    • 语法
      • 使用 Vue.component(tagName, options) 方法定义。
      • tagName 是组件的标签名。
      • options 是一个对象,包含组件的选项,如 templatedatamethods 等。
      • 全局组件定义后,可以在任何 Vue 实例中使用,无需额外注册。
  • 局部组件

    • 与全局组件不同,局部组件只能在定义它们的当前组件内部使用
    • 这种组件的创建通常是为了实现特定组件的特定功能或界面,因此具有更好的封装性,减少了与其他组件之间的耦合。
    • 语法components:{tagName, options}
      • 先定义一个包含组件选项的对象。
      • 在特定的 Vue 实例或组件的 components 选项中注册这个对象,并给它一个标签名。
      • 局部组件只能在它被定义的那个 Vue 实例或组件内部使用。

image-20240428153235277

<body>

<div id="app">
    <h1 v-text="info"></h1>
    <hr>
    <Child2></Child2>
    <hr>
    <Child1></Child1>

</div>

</body>

<script>

    Vue.component('Child2', { // 全局组件
        template: `
          <div>
            <h2 v-text="info"></h2>
          </div>`,
        data() {
            return {
                info: '全局组件',
            }
        },
    });

    let childComponent = { // 局部组件
        template: `
          <div><h2 v-text="info"></h2></div>`,
        data() {
            return {
                info: '局部组件',
            }
        },
    }

    var vm = new Vue({
        el: "#app",
        data: {
            info: '根组件',
        },
        components: {
            'Child1': childComponent // 局部组件在components中注册
        },
    })

</script>

(2)组件中的data

  • 当定义组件时,data应该是一个返回对象的函数,而不是直接返回一个对象。这样做的原因是,当Vue实例化一个组件时,它会调用这个data函数,从而确保每个实例都有它自己的数据状态

  • 举个例子,如果我们不将data定义为返回对象的函数,而是直接返回一个对象,那么多个组件实例将会共享这个对象,它们的状态将会相互影响:

Vue.component('MyComponent', {  
  // 错误的data定义方式  
  data: {  
    message: 'Hello'  
  },  
  template: '<div>{{ message }}</div>'  
});
  • 在上面的例子中,如果页面上有多个MyComponent的实例,那么它们会共享同一个data对象,这意味着改变一个实例的message属性也会影响其他实例。

  • 正确的做法是将data定义为一个函数,这样每个组件实例都会返回一个新的数据对象:

Vue.component('MyComponent', {  
  // 正确的data定义方式  
  data: function() {  
    return {  
      message: 'Hello'  
    }  
  },  
  template: '<div>{{ message }}</div>'  
});
  • 无论是全局组件还是局部组件,这个原则都是适用的。每个组件实例都需要有它自己的数据状态,因此data必须是一个返回对象的函数,而不是直接返回的对象。

【17】父子通信

(1)父传子–自定义属性props

  • 在Vue中,父组件向子组件传递数据通常是通过自定义属性(props)来实现的。
    • 父组件可以在子组件的标签上通过属性绑定(使用v-bind指令或简写为冒号:)来传递数据给子组件。
    • 子组件通过声明props来接收这些数据,并在组件内部使用。

image-20240428160635781

<body>
<div id="app">
    <child1 :message="messageParent"></child1>
</div>
</body>

<script>
    Vue.component('Child1', { // 全局组件
        template: `
          <div>
            <h2 v-text="info"></h2>
            <button @click="handleChange">切换显示父组件信息</button>
          </div>`,
        data() {
            return {
                info: '子组件信息',
            }
        },
        props: {
            message: {
                type: String,
                required: true
            }
        },
        methods: {
            handleChange() {
                this.info = this.message
            }
        }
    });

    var vm = new Vue({
        el: "#app",
        data: {
            messageParent: "父组件信息"
        },
    })
</script>
  • 在上面的例子中:
    • 父组件通过:message="messageParent"messageParent变量的值传递给子组件的message属性。
    • 子组件通过声明props: {message{ }}来接收这个属性,并在模板中使用{{ message }}来显示传递过来的数据。
    • 需要注意的是,子组件中声明的props应该明确类型,也可以指定是否必须传递(required),以及是否允许默认值(default)。

(2)子传父–自定义事件+$emit

  • 在Vue中,子组件向父组件传递数据通常是通过触发自定义事件来实现的。子组件可以使用$emit方法来触发一个事件,并传递数据给父组件。父组件则可以在子组件的标签上使用@v-on指令来监听这个事件,并定义处理函数来接收子组件传递的数据。

image-20240428171509727

<body>
<div id="app">
    <child1 @event="handleShow"></child1>
    <h3>子组件信息>>>:{{info}}</h3>
</div>
</body>

<script>

    Vue.component('Child1', { // 全局组件
        template: `
          <div>
            <button @click="handleSend">发信息到父组件</button>
          </div>`,
        data() {
            return {
                messageChild: "子组件信息"
            }
        },
        methods: {
            handleSend() {
                this.$emit('event', this.messageChild)
            }
        }
    });

    var vm = new Vue({
        el: "#app",
        data: {
            info: ""
        },
        methods: {
            handleShow(messageChild) {
                this.info = messageChild
            }
        }
    })

</script>
  • 子组件的模板包含一个按钮,当按钮被点击时,会触发handleSend方法。这个方法内部使用this.$emit('event', this.messageChild)来触发一个名为event的自定义事件,并将子组件内部的messageChild数据作为参数传递。

  • 父组件在模板中通过<child1 @event="handleShow"></child1>的方式使用子组件,并使用@event来监听子组件触发的event事件。当这个事件被触发时,父组件的handleShow方法会被调用,并且子组件传递过来的messageChild数据会作为参数传递给这个方法。

【18】ref属性

(1)介绍

  • ref属性用于给元素或子组件注册引用信息

    • 引用信息会被注册在父组件的$refs对象上。
    • 通过ref属性,我们可以方便地获取到子组件或DOM元素的引用,从而对其进行操作访问其属性和方法
  • 语法

    • ref属性的语法相对简单,只需在需要注册的元素或组件标签上添加ref属性,并为其指定一个唯一的名称即可。

    • <!-- 在普通元素上使用ref -->  
      <div ref="myDiv">普通标签</div>  
        
      <!-- 在子组件上使用ref -->  
      <child1 ref="myChild"></child1>
      
    • image-20240428180525877

(2)示例

image-20240428181439644

image-20240428181609054

<body>
<div id="app">
    <child1 ref="myChild"></child1>
    <h3>子组件信息>>>:{{info}}</h3>
    <button @click="handleShow">显示并操作ref内容</button>
</div>
</body>

<script>
    Vue.component('Child1', { // 全局组件
        template: `
          <div>
            <P>子组件信息:{{ messageChild }}</P>
          </div>`,
        data() {
            return {
                messageChild: "子组件信息"
            }
        },
    });
    var vm = new Vue({
        el: "#app",
        data: {
            info: ""
        },
        methods: {
            handleShow(messageChild) {
                this.info = this.$refs.myChild.messageChild + '-----'
                this.$refs.myChild.messageChild = this.info
            }
        }
    })
</script>

【19】动态组件

(1)component标签

  • <component :is="组件名"></component>

    • <component>是一个特殊的Vue内置元素,它可以根据一个动态的组件名来渲染一个组件。

    • 我们可以通过is属性来动态地改变要渲染的组件。

image-20240428183410623

<body>
<div id="app">
    <button @click="isShow='goods'">显示商品信息</button>
    <button @click="isShow='order'">显示订单信息</button>
    <button @click="isShow='backend'">显示后台信息</button>
    <hr>
    <component :is="isShow"></component>
</div>
</body>
<script>
    let goods = {template: `<h2>商品信息</h2>`}
    let order = {template: `<h2>订单信息</h2>`}
    let backend = {template: `<h2>后台信息</h2>`}
    var vm = new Vue({
        el: "#app",
        data: {
            isShow: "goods"
        },
        components: {
            goods, order, backend
        }
    })
</script>

(2)keep-alive组件

  • <keep-alive>是一个包裹组件,它可以使被包含的组件保持状态,避免重新渲染。这对于性能优化和用户体验的提升非常有用,特别是在组件切换频繁的场景下。
  • 在使用 keep-alive 时,需要注意以下几点:
    1. 包裹单个组件keep-alive 通常直接包裹一个动态组件 <component :is="...">,以缓存该动态组件的不同状态。
    2. include 和 exclude:通过 include 属性,你可以指定哪些组件名需要被缓存;通过 exclude 属性,你可以指定哪些组件名不需要被缓存。这两个属性都接受一个字符串或正则表达式数组。
    3. max 属性:通过 max 属性,你可以限制同时被缓存的组件实例的最大数量。当这个数量达到上限时,新创建的组件实例会替换掉最不常用的组件实例。

image-20240428184331606

<body>
<div id="app">
    <button @click="isShow='goods'">显示商品信息</button>
    <button @click="isShow='order'">显示订单信息</button>
    <button @click="isShow='backend'">显示后台信息</button>
    <hr>
    <keep-alive include="">
        <component :is="isShow"></component>
    </keep-alive>

</div>
</body>
<script>
    let goods = {template: `
<div>
<h2>商品信息</h2>
<input type="text">
</div>`}
    let order = {template: `<h2>订单信息</h2>`}
    let backend = {template: `<h2>后台信息</h2>`}
    var vm = new Vue({
        el: "#app",
        data: {
            isShow: "goods"
        },
        components: {
            goods, order, backend
        }
    })
</script>

【20】插槽slot

(1)介绍

  • 插槽(Slot)允许开发者将内容插入到指定的位置,从而使模板分块,具有模块化的特质和更大的重用性。

    • 插槽的显示与否以及如何显示是由父组件来控制的
    • 插槽在哪里显示则由子组件来决定
  • 分类:

    • 匿名插槽

      • 概念:没有为插槽指定名称的插槽。
      • 使用方法:通过<slot></slot>标签可以在子组件中定义匿名插槽。在父组件中使用子组件时,组件中的内容会填充到所有匿名插槽的位置。
    • 具名插槽

      • 概念:为插槽设置名字的插槽,用于接收特定名称的内容。

      • 使用方法:在定义具名插槽时,需要给插槽一个名字,如<slot name="header"></slot>。在父组件中,使用v-slot指令来传递内容到指定的具名插槽,例如v-slot:header或者简写为#header

(2)使用

  • 匿名插槽

image-20240428190252994

  • 具名插槽

image-20240428190558767

<body>
<div id="app">
    <h2>匿名插槽</h2>
    <goods>
        <div>头部信息</div>
        <div>尾部信息</div>
    </goods>

    <hr>
    <h2>具名插槽</h2>
    <order>
        <div slot="foot">尾部信息</div>
        <div slot="head">头部信息</div>
    </order>

</div>
</body>
<script>
    let goods = {
        template: `
<div>
<slot></slot>
<h3>商品信息</h3>
<slot></slot>
</div>`
    }
    let order = {
        template: `
<div>
<slot name="head"></slot>
<h3>订单信息</h3>
<slot name="foot"></slot>
</div>`
    }
    var vm = new Vue({
        el: "#app",
        components: {
            goods, order
        }
    })
</script>

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值