Vue之组件自定义v-model & 插槽的相关使用

1,580 阅读3分钟

写在前面

最近有点忙,也一直在思考该写点什么。加上最近天气有点冷,始终伸不出手,所以一直耽误到现在。想想还是继续之前的文章来重新学习一些关于vue的一些东西。

自定义组件的 v-model

通常v-model指令用在一些表单控件上供我们做双向数据绑定。实际上这个指令是表单控件的valueinput(这里只列举input) 的语法糖。这样我们不用像React中那样去自己监听控件的输入事件。但是有的时候可能需要把表单控件封装起来作为一个独立的组件使用,然后再这个组件使用的地方使用v-model。例如有一个选择国家的组件需要复用:

  • custom-select.vue
<template>
  <div class="custom-select">
    <select :value="value" @change="$emit('change', $event.target.value)">
      <option value="">请选择</option>
      <option value="1">中国</option>
      <option value="2">美国</option>
      <option value="3">法国</option>
      <option value="4">日本</option>
    </select>
  </div>
</template>

<script>
export default {
  model: {
    prop: "value",
    event: "change",
  },
  props: ["value"],
};
</script>

<style>
</style>
  • Home.vue
<custom-select v-model="selectVal"></custom-select>

插槽

插槽 slot在组件化开发中非常实用,能够适应很多个性化的业务场景。通俗来讲,我们写一个自定义组件,未来可能你期望在这个组件标签的中间区域插入一些内容;默认情况下,如果你不预先挖一个坑的话,那么你插入的东西都将被抛弃。

  • 默认坑位

    默认情况下,如果你什么都不做,坑都不挖。那么不好意思,Vue不会理睬你~。如果你在定义组件的时候写了一个特殊的标签 <slot></solt>,那么vue就把他当成了默认坑位,后面在使用的时候位于自定义标签内部的元素都会默认放在这个坑位的位置。当然如果你期望给一个默认值,你可以把默认内容丢在slot内部,这样将来你在使用自定义组件的时候,可以不用填坑,而是使用默认值。

  • 插槽作用域

    虽说坑位现在有了,但是现在有个问题就是坑位是在自定义组件中占住的,然而实际入坑的内容却是在使用组件的时候在组件标签内部插入的。默认情况下,父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

  • 命名坑位

    有很多时候可能不只一个坑,你可能需要多个坑,那么此时很明显默认坑位已经满足不了你的需求了。需要做的是在挖坑的时候给每个坑取一个漂亮的名字<slot name="坑名"></slot>,后面填坑的时候可以给你想填的内容的最外层元素(一般会写个template),然后通过v-slot:坑名的方式开始填坑。这样你填的内容将会插入到指定名称的坑位中去。

  • 作用域坑位(开放坑位)

    有时候你可能需要在填坑的内容中期望使用自定义组件里面的状态,此时如果坑位不给你提供这样的一个接口,你是无法使用其内部的状态的。组件内部在写slot的时候通过数据绑定的方式将其内部变量暴露出来,而使用者在使用的时候需要接收,通过<template v-slot:坑名="slotPorps"></template>的形式使用。注意暴露出来的数据会挂载到你接收的这个变量上。

最后通过一个示例来演示一下怎么简单利用插槽实现类似bootstrap的面板功能。

  • 组件panel
<template>
  <div class="panel" v-if="show">
    <div class="panel-heading">
      <slot name="header"></slot>
    </div>

    <div class="panel-body">
      <slot></slot>
    </div>
    
    <div class="panel-footer">
      <slot name="footer" :content="footerText"></slot>
    </div>
    <span class="panel-close" @click="$emit('update:show',false)">X</span>
  </div>
</template>

<script>
export default {
  props:{
    show:Boolean,
    default:false
  },
  data(){
    return {
      footerText:'footer'
    }
  }
};
</script>

<style scoped>
.panel {
  position: relative;
  width: 100%;
  background-color: #fff;
  border-radius: 4px;
  border: 1px solid transparent;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
}

.panel-body {
  padding: 10px 15px;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
  border-bottom: 1px solid transparent;
}
.panel-success {
  border-color: #d6e9c6;
}
.panel-success .panel-heading {
  background-color: #d6e9c6;
}
.panel-close {
  position: absolute;
  right: 5px;
  top: 5px;
  cursor: pointer;
}
</style>
  • 页面Home使用
<button @click="show = true">消息提示</button>
<panel class="panel-success" :show.sync="show">
  <template v-slot:header> 消息提示 </template>
  <div>
    <p>Panel content</p>
    <p>Panel content</p>
    <p>Panel content</p>
    <p>Panel content</p>
    <p>Panel content</p>
    <p>Panel content</p>
    <p>Panel content</p>
  </div>
  <template v-slot:footer="{ content }">1111-{{ content }}</template>
</panel>

最后

本文主要介绍了关于组件自定义v-model以及slot的一些内容。这些东西在日常开发中使用的频率还是相当高的。希望可以帮助到跟我一样菜的菜鸟~~。

参考

自定义组件的 v-model

插槽