封装一个 sidebar 组件

在平时工作中,免不了需要我们根据业务需求去封装相应的组件,那这篇我们就来封装一个 YuSidebar 组件,关键是 install 方法

记重点:

  1. 如果需要写一个vue的插件
  2. 就向外输出一个对象
  3. 这个对象必须要有一个方法,方法名为install
  4. 外面调用插件,Vue.use(插件模块)
  5. 内部install方法就会执行

以下就是我封装的 YuSidebar 的说明文档以及代码实现:

说明文档 readme

引入

import Vue from 'vue'
import {YuSidebar, YuSidebarItem} from './plugin'
Vue.use(YuSidebar).use(YuSidebarItem);

代码演示

基础用法

  <yu-sidebar v-model="activeKey">
    <yu-sidebar-item title="标签 1"></yu-sidebar-item>
    <yu-sidebar-item title="标签 2"></yu-sidebar-item>
    <yu-sidebar-item title="标签 3"></yu-sidebar-item>
    <yu-sidebar-item title="标签 4"></yu-sidebar-item>
  </yu-sidebar>

  export default {
    data(){
      return {
        activeKey: 2
      }
    }
  }

提示信息

  <yu-sidebar v-model="activeKey">
    <yu-sidebar-item title="标签 1"></yu-sidebar-item>
    <yu-sidebar-item title="标签 2" info="5"></yu-sidebar-item>
    <yu-sidebar-item title="标签 3" dot></yu-sidebar-item>
    <yu-sidebar-item title="标签 4" info="99+"></yu-sidebar-item>
  </yu-sidebar>

禁用选项

  <yu-sidebar v-model="activeKey">
    <yu-sidebar-item title="标签 1" disabled></yu-sidebar-item>
    <yu-sidebar-item title="标签 2"></yu-sidebar-item>
    <yu-sidebar-item title="标签 3"></yu-sidebar-item>
    <yu-sidebar-item title="标签 4"></yu-sidebar-item>
  </yu-sidebar>

切换导航项添加自定义事件,得到索引

<yu-sidebar v-model="activeKey" @change="changeAction">
    <yu-sidebar-item title="标签 1"></yu-sidebar-item>
    <yu-sidebar-item title="标签 2" @click="clickAction"></yu-sidebar-item>
    <yu-sidebar-item title="标签 3"></yu-sidebar-item>
    <yu-sidebar-item title="标签 4"></yu-sidebar-item>
  </yu-sidebar>

  export default {
    data(){
      return {
        activeKey: 2
      }
    },
    methods: {
      // 点击返回当前点击的 index
      changeAction(index) {
        console.log('sideBar当前点击的是' + index);
      },
      // 当前点击的 索引
      clickAction(index) {
        console.log('sidebarItem 中点击的' + index);
      }
    }
  }

url跳转 / 路由跳转

  <yu-sidebar v-model="activeKey" @change="changeAction">
    <yu-sidebar-item title="标签 1"></yu-sidebar-item>
    <yu-sidebar-item title="标签 2" info="5" @click="clickAction" :to="{ path: 'home' }"></yu-sidebar-item>
    <yu-sidebar-item title="标签 3" dot url="http://www.baidu.com"></yu-sidebar-item>
    <yu-sidebar-item title="标签 4" info="99+" to="'home'" replace></yu-sidebar-item>
  </yu-sidebar>

API

Sidebar Props
参数 说明 类型 默认值
v-model 当前导航项的索引 string / number(类型) 0
Sidebar Events
事件名 说明 回调参数
change 切换导航项时触发 index当前导航项的索引(回调参数)
SidebarItem Props
参数 说明 类型 默认值
title 内容 string ‘’
dot 是否显示右上角小红点 boolean false
info 右上角徽标的内容 string / number -
disabled 是否禁用该项 boolean false
url 点击后跳转的链接地址 string -
to 点击后跳转的目标路由对象 string / object -
replace 是否在跳转时替换当前页面历史 boolean false
SidebarItem Events
事件名 说明 回调参数
click 点击时触发 index 当前导航项的索引

以上就是使用方法,那我们在 App.vue 中使用一下

<template>
<div id="app">

  <yu-sidebar v-model="activeKey" @change="changeAction">
    <yu-sidebar-item title="标签 1" disabled></yu-sidebar-item>
    <yu-sidebar-item title="标签 2" info="5" @click="clickAction" :to="{ path: 'home' }"></yu-sidebar-item>
    <yu-sidebar-item title="标签 3" dot url="http://www.baidu.com"></yu-sidebar-item>
    <yu-sidebar-item title="标签 4" info="99+" to="'home'" replace></yu-sidebar-item>
  </yu-sidebar>

</div>
</template>

<script>
import Vue from 'vue'
import {YuSidebar, YuSidebarItem} from './plugin'
Vue.use(YuSidebar).use(YuSidebarItem);
export default {
  data(){
    return {
      activeKey: 2
    }
  },
  methods: {
    // 点击返回当前点击的 index
    changeAction(index) {
      console.log('sideBar当前点击的是' + index);
    },
    // 当前点击的 索引
    clickAction(index) {
      console.log('sidebarItem 中点击的' + index);
    }
  }
}
</script>

<style>
html, body {
  width: 100%;
  height: 100%;
}
#app {
  width: 100%;
  height: 30%;
}
</style>

出来以下图示效果:
QQ图片20191106193107.png

封装组件代码实现:

YuSidebar.vue

<template>
  <nav class="yuSidebar">
    <slot />
  </nav>
</template>

<script>
export default {
  name: 'yu-sidebar',
  props: {
    value: {
      type: Number,
      default: 0
    },

  },
  data() {
    return {

    }
  },
  methods: {
    // 根据下标来选中
    selectByIndexAction(flag) {
      // 触发外部的 input 事件 双向绑定
      this.$emit('input', flag);
      // 除外外部的 change 事件,传入索引
      this.$emit('change', flag);

      // 循环遍历子节点,改变当前 flag active
      this.$children.forEach((child, index) => {
        if(index === flag) { //选中
          child.isActive = true;
        }else { // 不选中
          child.isActive = false;
        }
      });
    }
  },
  mounted() {
    // 开始默认的选中下标
    this.$children[this.value].isActive = true;
    // 给每个 SidebarItem 添加下标 --- 索引
    this.$children.forEach((child, index) => {
      child.index = index;
    });
  }
}
</script>

<style scoped>
.yuSidebar {
  width: 85px;
  margin-left: 16px;
  display: flex;
  flex-direction: column;
}
</style>

YuSidebarItem.vue

<template>
  <a :href="url" class="yuSidebarItem" @click="!disabled && selectAction()" 
  :class="{active: isActive, disabled: disabled}">
  <span>
    {{title}}
    <em class="yu-info yu-info-dot" v-if="dot" ></em>
    <em class="yu-info" v-if="info">{{info}}</em>
  </span>
</a>
</template>

<script>
export default {
  name: 'yu-sidebar-item',
  props: {
    title: String, // 标签名
    disabled: {
      type: Boolean,
      default: false
    },
    dot: {
      type: Boolean,
      default: false
    },
    info: {
      type: [Number, String],
      default: '',
    },
    url: {
      type: String,
      default: 'javascript:;'
    },
    to: {
      type: [String, Object],
      default: ''
    },
    replace: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      isActive: false, // 是否选中
    }
  },
  methods: {
    // 点击的时候选中
    selectAction() {
      this.$parent.selectByIndexAction(this.index);
      this.$emit('click', this.index);

      // 根据传进来的路由跳转 
      if(to != '') {
        if(replace) {
          // 使用 replace 而不是使用 push
          this.$router.replace(this.to);
        }else {
          this.$router.push(this.to);
        }
      }
      
    }
  }
}
</script>

<style scoped>
.yuSidebarItem {
  text-decoration: none;
  display: block;
  flex: 1;
  color: #555;
  list-style: none;
  background-color: #fafafa;
  padding: 20px 12px 20px 8px;
  box-sizing: border-box;
  border-left: 3px solid transparent;
  overflow: hidden;
  font-size: 14px;
  line-height: 20px;
  word-wrap: break-word;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.yuSidebarItem span {
  position: relative;
  display: inline-block;
  font-size: 14px;
  line-height: 20px;
  /* padding: 4px; */
}
/* 选中的样式 */
.yuSidebarItem.active {
  border-color: #ee0a24;
  color: #323233;
  font-weight: 500;
  background-color: #fff;
}
/* 不能点击的样式 */
.yuSidebarItem.disabled {
  color: #c8c9cc;
}
/* 小红点的样式 */
.yu-info {
  position: absolute;
  top: 0;
  right: 0;
  -webkit-transform: translate(50%, -50%);
  transform: translate(50%, -50%);
  box-sizing: border-box;
  min-width: 16px;
  padding: 0 3px;
  color: #fff;
  font-weight: 500;
  font-size: 12px;
  font-family: PingFang SC, Helvetica Neue, Arial, sans-serif;
  line-height: 14px;
  text-align: center;
  border: 1px solid #fff;
  -webkit-transform-origin: 100%;
  transform-origin: 100%;
  background-color: #ee0a24;
  border-radius: 16px;
}
.yu-info-dot {
  width: 8px;
  min-width: 0;
  height: 8px;
  background-color: #ee0a24;
  border-radius: 100%;
}
</style>

封装插件 index.js

// 如果需要写一个vue的插件。
// 就向外输出一个对象
// 这个对象必须要有一个方法,方法名为install
// 外面调用插件,Vue.use(插件模块)
// 内部install方法就会执行
import yuSidebar from './YuSidebar.vue'
import yuSidebarItem from './YuSidebarItem.vue'

export default {
  install(Vue){
    Vue.component(yuSidebar.name, yuSidebar);
    Vue.component(yuSidebarItem.name, yuSidebarItem);
  }
}

export const YuSidebar = {
  install(Vue){
    Vue.component(yuSidebar.name, yuSidebar);
  }
};

export const YuSidebarItem  = {
  install(Vue){
    Vue.component(yuSidebarItem.name, yuSidebarItem);
  }
};

好啦,一个自定义的 sidebar 组件就封装好啦,下次再见 ~

发布了18 篇原创文章 · 获赞 27 · 访问量 554

猜你喜欢

转载自blog.csdn.net/weixin_44691775/article/details/104426307