自己编写vue tabs组件编写

傷城~ 2022-09-05 12:37 249阅读 0赞

想自己编写标签页组件,点击标签切换显示对应的内容,使用方式如下

  1. <mytabs>
  2. <mytab-pane label="Notice">
  3. <notice></notice>
  4. </mytab-pane>
  5. <mytab-pane label="Emergency Contact">
  6. <contact></contact>
  7. </mytab-pane>
  8. </mytabs>

实现原理

父组件嵌套子组件,子组件内部通过prop属性指定标签名称,通过slot自定义标签要显示的内容
子组件
this.$slots.default 获取slot插入的所有组件vnode
通过vnode.componentOptions.propsData 获取组件内部的props属性
组件内的内容通过v-if绑定data属性控制显示

mytabs.vue

  1. <template>
  2. <div class="tabs">
  3. <ul>
  4. <li v-for="(item, index) in labels" @click="clickTab(item, index)" :key="index" :class="[item == currentName ? 'active' : '']" >
  5. {
  6. { item }}
  7. </li>
  8. </ul>
  9. <slot></slot>
  10. </div>
  11. </template>
  12. <script> export default { name: "mytabs", data() { return { currentName: null, panes: [], labels: [], }; }, methods: { clickTab(name, index) { // debugger; //标签名显示选中 this.currentName = name; }, calcPaneInstances() { if (this.$slots.default) { debugger; const paneSlots = this.$slots.default.filter( (vnode) => vnode.tag && vnode.componentOptions && vnode.componentOptions.Ctor.options.name === "mytabPane" ); const panes = paneSlots.map( ({ componentInstance }) => componentInstance ); //标签切换 currentName set也会触发updated,所以需要判断slots是不是真的变化了 const panesChanged = !( panes.length === this.panes.length && panes.every((pane, index) => pane === this.panes[index]) ); if (panesChanged) { this.panes = panes; } } else if (this.panes.length !== 0) { debugger; this.panes = []; } debugger; }, }, //收集子组件mytabPane的label,不能写在created mounted() { debugger; this.calcPaneInstances(); }, updated() { // 初次加载的时候 //页面刚开始的时候还没有获取到用户权限信息,用户权限信息加载完后slot会变化 debugger; //currentName set也会触发updated this.calcPaneInstances(); }, watch: { //页面刚开始的时候还没有获取到用户权限信息,用户权限信息加载完后slot会变化 panes(newVal, oldVal) { debugger; this.labels = newVal.map((t) => t.label); if (this.labels.length > 0) { const contained = this.labels.some((t) => t === this.currentName); if (!contained) { this.currentName = this.labels[0]; } } else { this.currentName = null; } }, }, }; </script>
  13. <style lang="scss" scoped> .tabs { ul { margin-bottom: 10px; li { display: inline-block; margin: 0 10px; padding: 5px 0; color: rgb(182, 182, 182); cursor: pointer; } .active { border-bottom: 2px solid #931c7f; color: rgb(10, 1, 1); } } } </style>

mytabPan.vue

  1. <template>
  2. <div v-show="active">
  3. <slot></slot>
  4. </div>
  5. </template>
  6. <script> export default { name: "mytabPane", data() { return { flag: false, }; }, props: { label: { type: String, default: null, }, value: { type: String, default: null, }, }, computed: { active() { const active = this.$parent.currentName === this.label; return active; }, }, }; </script>
  7. <style scoped> </style>

使用

发表评论

表情:
评论列表 (有 0 条评论,249人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Vue Tab 再探究

    初学 Vue 的时候,发现用 Vue 来写 Tab 组件是如此简单,利用“数据驱动”的思路还真和 js 控制 dom 不一样。请见下面第一版的代码,没有 js dom 那样 f

    相关 如何自己编写Makefile

    相信很多朋友都有过这样的经历,看着开源项目中好几页的makefile文件,不知所云。在日常学习和工作中,也有意无意的去回避makefile,能改就不写,能用ide就用ide。其