Vue(五):动态组件&插槽&自定义指令

目录

一、动态组件

1.1 什么是动态组件

1.2 动态切换组件的显示与隐藏

1.3 使用keep-alive保持状态

1.4 keep-alive对应的生命周期

1.5 keep-alive的include属性

1.6 组件注册名称和组件声明时name的区别

二、插槽

2.1 什么是插槽

2.2 v-slot

2.2.1 v-slot的基本使用

2.2.2 v-slot的简写是#

2.2.3 插槽的默认内容

2.3 具名插槽

2.4 作用域插槽

2.4.1 作用域插槽的基本用法

2.4.2 作用域插槽的解构赋值

2.4.3 基于插槽改造购物车案例

三、自定义指令

3.1  什么是自定义指令

3.2 自定义指令分类

3.2.1 私有自定义指令----基本使用

3.2.2 私有自定义指令---通过binding.value获取指令绑定的值

3.2.3 私有自定义指令---update函数

 3.3 自定义指令----函数简写(注意前提)

 3.4 全局自定义指令


一、动态组件

1.1 什么是动态组件

动态组件指的是动态切换组件的显示与隐藏

1.2 动态切换组件的显示与隐藏

vue提供了一个内置的<component>组件,专门用来实现动态组件的渲染,控制显示页面的属性是is。示例代码如下:

 <component :is="shownam"></component>
<template>
  <div id="app">
  <h1>App.vue</h1>
  <div>
    <button @click="shownam = 'Left'">展示Left</button>
    <button @click="shownam = 'Right'">展示Right</button>
  </div>
  <div>
    <!-- is属性用来控制显示的组件 -->
    <component :is="shownam"></component>
 </div>
  </div>
</template>

<script>
import Left from '@/components/left.vue'
import Right from '@/components/right.vue'
export default {
  components: {
    Left,Right
  },
  data() {
    return {
        shownam: ''
    }
  }
}
</script>

<style lang="less" scoped>
</style>

实现效果如下:点击展示Left按钮,展示Left.vue页面。电视展示Right按钮,展示Right.vue页面 .效果类似于移动端App的底端Tabbar

1.3 使用keep-alive保持状态

 问题描述:若在left.vue页面中添加加1的按钮,加到N后点击展示Right按钮,再点击展示left按钮。此时数字又变成了1。

 解决:采用keep-alive解决上述问题。将要保持的标签外部加keep-alive标签即可

注: keep-alive可以把内部的组件进行缓存,而不是销毁组件

1.4 keep-alive对应的生命周期

当组件被缓存时,会自动触发组件的deactivated生命周期函数

当组件被激活时,会自动触发组件的activated生命周期函数

当组件第一次被创建的时候,既会执行created生命周期,也会执行activated生命周期

但是,当组件被激活的时候,只会触发activated生命周期,不再触发created生命周期,因为组件没有被重新创建。

注:只有加了keep-alive标签的,才有deactivated和activated生命周期函数。

注:生命周期函数应该在子页面中编写

app.vue:

<template>
  <div id="app">
  <h1>App.vue</h1>
  <div>
    <button @click="shownam = 'Left'">展示Left</button>
    <button @click="shownam = 'Right'">展示Right</button>
  </div>
  <div>
    <!-- is属性用来控制显示的组件 -->
    <keep-alive>
        <component :is="shownam"></component>
    </keep-alive>
 </div>
  </div>
</template>

<script>
import Left from '@/components/left.vue'
import Right from '@/components/right.vue'
export default {

  components: {
    Left,Right
  },
  data() {
    return {
        shownam: ''
    }
  }
}
</script>

<style lang="less" scoped>
</style>

left.vue:

<template>
<div id="left">
    <h3>LEFT组件-----{{ count }}</h3>
    <button @click="count += 1">+1</button>
</div>
</template>
<script>
export default {
    data() {
        return {
            count: 0
        }
    },
  created() {
    console.log('left---created生命周期函数')
  },
  activated() {
    console.log('left---activated生命周期函数')
  },
  deactivated() {
    console.log('left---deactivated生命周期函数')
  },
}
</script>

<style lang="less" scoped>
#left {
    background-color:rgb(111, 0, 255);
    // width: 50%;
    // height: 400px;
}

</style>

1.5 keep-alive的include属性

include属性用来指定:只有名称匹配的组件会被缓存。多个组件名之间用英文逗号分隔

 exclude用来指定哪些不被缓存。include和exclude不能同时使用

1.6 组件注册名称和组件声明时name的区别

组件的注册名称(App.vue):

 组件声明时的Name(Left.vue)

当提供了name属性后,组件的名称就是name属性值。

区别:(1)组件的注册名称的主要应用场景是:以标签的形式,把注释好的组件,渲染和使用到页面结构中。

(2)组件声明时候的“name”名称的主要应用场景,结合<keep-alive>标签实现组件缓存功能,以及在调试工具中看到组件的name名称

二、插槽

2.1 什么是插槽

插槽(Slot)是vue为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望用户指定的内容定义为插槽。

插槽使用示例:

(1)left.vue中用<slot>标签占位,声明一个插槽

 

(2) App.vue中用p标签填充slot区域

 效果如下:

2.2 v-slot

2.2.1 v-slot的基本使用

注:vue官网规定,每一个slot插槽,都要有一个name名称,如果省略了slot的name属性,则有一个默认的名称叫做default。

<slot name="default"></slot>

默认情况下,在使用组件的时候,提供的内容都会填充到名字为default的插槽之中

如果要把内容填充到指定名称的插槽中,需要使用v-slot这个指令。v-slot:插槽名称

v-slot不能直接用在元素身上,必须用在template标签上。

template只是一个虚拟标签,不会被渲染成HTML元素

v-slot使用示例如下:

(1)left.vue中定义插槽,名称为test

 (2)app.vue中使用插槽,通过v-slot 指定插槽名称

2.2.2 v-slot的简写是#

2.2.3 插槽的默认内容

若想指定默认内容。则操作如下:

此时若注释app.vue中传入的内容,页面显示的是“slot的默认内容”。若不去除,则显示的是app.vue中指定的插槽内容。

2.3 具名插槽

具名插槽,顾名思义,就是给每个插槽都起对应的名称,方便用户后期渲染,示例如下:

(1)App.vue

<template>
  <div id="app">
  <h1>App.vue</h1>
  <div>
  <Article>
      <template #title>
          <h3>一首诗</h3>
      </template>

      <template #content>
        <div>
          <p>大海</p>
          <p>土地</p>
        </div>
      </template>
      <template #author>
        <div>作者:xxxx</div>
      </template>
  </Article>
  </div>
  <div>

 </div>
  </div>
</template>

<script>
import Article from '@/components/Article.vue'
export default {

  components: {
    Left,
    Right,
    Article
  },
}
</script>

<style lang="less" scoped>
</style>

(2)Article.vue

<template>
  <div class="Article-container">
<!-- 文章标题 -->
<div class="header-box">
    <slot name="title"></slot>
</div>
<!-- 文章内容 -->
<div class="content-box">
    <slot name="content"></slot>
</div>

<!-- 文章作者 -->
<div class="footer-box">
    <slot name="author"></slot>
</div>
  </div>
</template>

<script>
export default {
    name: 'Article'
}
</script>

<style lang="less" scoped>
.Article-container {
    >div {
        min-height: 150px;
    }
    .header-box {
        background-color: pink;
    }
    .content-box {
        background-color: powderblue;
    }
    .footer-box {
        background-color: sandybrown;
    }
    
}
</style>

效果如下:

2.4 作用域插槽

2.4.1 作用域插槽的基本用法

作用域插槽:在封装组件时,为预留的<slot>提供属性对应的值,这种用法称为“作用域插槽”

2.4.2 作用域插槽的解构赋值

Article.vue:

<template>
  <div class="Article-container">
<!-- 文章标题 -->
<div class="header-box">
    <slot name="title"></slot>
</div>
<!-- 文章内容 -->
<div class="content-box">
    <slot name="content" msg="hello" :user="userinfo"></slot>
</div>

<!-- 文章作者 -->
<div class="footer-box">
    <slot name="author"></slot>
</div>
  </div>
</template>

<script>
export default {
    name: 'Article',
    data() {
        return {
            userinfo: {
                name: 'zs',
                age: 18
            }
        }
    }
}
</script>

<style lang="less" scoped>
</style>

App.vue:

<template>
  <div id="app">
  <h1>App.vue</h1>
  <div>
  <Article>
      <template #title>
          <h3>一首诗</h3>
      </template>

      <template #content="scope">
        <div>
          <p>大海</p>
          <p>土地</p>
          <p>{{scope.user}}</p>
        </div>
      </template>
      <template #author>
        <div>作者:xxxx</div>
      </template>
  </Article>
  </div>
  <div>
 </div>
  </div>
</template>

<script>
import Left from '@/components/left.vue'
import Right from '@/components/right.vue'
import Article from '@/components/Article.vue'
export default {

  components: {
    Left,
    Right,
    Article
  },

}
</script>

<style lang="less" scoped>
</style>

如上,Article.vue中传入了一个对象,在Article.vue设置属性为userinfo对象

App.vue中接收:

 也可采用解构赋值:

2.4.3 基于插槽改造购物车案例

利用插槽实现数量加减的功能:

 在Goods.vue中添加<slot>

 (2)App.vue中渲染插槽内容

 

 

此时页面效果实现,但是点击加减无反应,且原始的数量值都是1

采用插槽后,Counter.vue属于App.vue的子组件,而不是孙子组件,不需要再像之前一样,借助Goods.vue传值。

(1)默认值属于父向子传值,采用自定义属性的方法。

(2)点击+ / - 属于子向父传值,采用自定义方法。代码如下:

 改造后的Counter.vue

<template>
  <div class="counter-container">
      <!-- 减1的按钮 -->
      <!-- 执行值减1,并将值传递给组件App.vue,此处采用的是eventBus -->
      <button class="btn" @click="minus">-</button>
      <!-- 购买的数量 -->
      <!-- 购买数量是父组件Goods组件传递过来的 -->
      <span class="number-box">{{ count }}</span>
      <!-- 加1的按钮,并将值传递给组件App.vue,此处采用的是eventBus-->
      <button class="btn" @click="add">+</button>
  </div>
</template>

<script>
import bus from '@/components/eventBus.js'
export default {
    props: {
        // 接收商品的id值,将来使用eventBus方案,把数量传递到App.vue的时候,需要通知App组件,
        // 更新的是哪个商品的数量
        id: {
            type: Number,
            required: true
        },
        // 购买的数量,父组件App.vue赋值
        count: {
            default: 1,
            type: Number
        }
    },
    methods: {
        minus() {
            // 要发送App的数据格式为{id,value}
            // 减去的时候等于0的时候,不能再点
            if(this.count - 1 === 0) return 
            this.$emit('send',this.count - 1)
        },
        add() {
            this.$emit('send',this.count + 1)
        }
    }
}
</script>

<style lang="less" scoped>
.number-box {
    min-width: 30px;
    text-align: center;
    margin: 0 5px;
}
</style>

App.vue:

methods中定义getNewNum方法,将传过来的值,赋值给对应id项

三、自定义指令

3.1  什么是自定义指令

vue官方提供了v-text,v-for,v-if等常用的指令,还允许开发者自定义指令。

3.2 自定义指令分类

(1)私有自定义指令 

(2)全局自定义指令

3.2.1 私有自定义指令----基本使用

在每个vue组件中,可以在directives节点下声明私有自定义指令,示例代码如下:

(1)定义:在directives节点下定义自定义指令

 (2)使用:使用时在自定义指令前加v-

3.2.2 私有自定义指令---通过binding.value获取指令绑定的值

 若想在v-color后加属性值,则directives中需要借助binding形参,binding.value就是v-color获取到的值,用法如下:

 

3.2.3 私有自定义指令---update函数

bind函数只调用一次:当指令第一次绑定到元素时调用,当DOM更新时bind函数不会被触发。update函数会在每次DOM更新时被调用。示例代码如下:

在App.vue中创建按钮,更改color的值,更改后color的值更改成功,但页面无更新。原因是bind函数只在第一次绑定元素时生效,后期值更新后不生效。需要借助update函数实现:

 注:bind和update函数都需要,bing函数负责第一次绑定元素,update负责后期更新

 3.3 自定义指令----函数简写(注意前提)

 若bind和update函数内部的语句一样,可简写:

 

 3.4 全局自定义指令

全局共享自定义指令通过Vue.directive()在main.js中声明,示例代码如下:

参数1:字符串,表示全局自定义指令的名字

参数2:对象,用来接收指令的参数值

可简写为:

注:过滤器和自定义指令一般都全局定义!!!!

小知识

main.js中这个配置用来定义控制台是否展示提示 :

提示在上线前将模式修改为production,仅为提示,无实际意义,默认为false 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值