封装一个简易的面包屑组件

491 阅读1分钟

对这个效果做一个封装

image.png

需要准备两个.vue文件,这两个文件都需要在全局注册

1.bread.vue

<script>
// import { h } from 'vue'
export default {
  name: 'XtxBread',
  render() {
    // Vue2中h函数是render的形参
    // Vue3的h函数是按需导入的
    const slotContent = this.$slots.default().filter(item => item.type.name === 'XtxBreadItem')
    const children = []
    slotContent.forEach((item, i) => {
      console.log(item.type.name)
      // 添加单个面包屑组件
      children.push(item)
      if (i < slotContent.length - 1) {
        // 添加一个小箭头(最后一个不添加)
        // const iTag = h('i', { class: 'iconfont icon-angle-right' }, null)
        // children.push(iTag)
        children.push(<i className="iconfont icon-angle-right"></i>)
      }
    })
    // return h('div', { class: 'xtx-bread' }, children)
    return <div className="xtx-bread">{children}</div>
  }
}
// JSX js的一种扩展(React):就是在js中写HTML标签
// const info = <div>hello</div>
// const msg = 'abc'
// const info = (
//   <div>
//     <div className='active'>hello</div>
//     <div>{msg}</div>
//   </div>
// )
// function foo (tag) {
//   return (
//     <div>
//       <div>{tag}</div>
//       <div>tom</div>
//     </div>
//   )
// }
// const tag = foo(<div>hi</div>)
/**
 * <div>
      <div><div>hi</div></div>
      <div>tom</div>
    </div>
 */
</script>

<style scoped lang="less">
.xtx-bread {
  display: flex;
  padding: 25px 10px;
  :deep(&-item) {
    a {
      color: #666;
      transition: all 0.4s;
      &:hover {
        color: @xtxColor;
      }
    }
  }
  :deep(i) {
    font-size: 12px;
    margin-left: 5px;
    margin-right: 5px;
    line-height: 22px;
  }
}
</style>

2.bread-item.vue

<template>
  <div class="xtx-bread-item">
    <RouterLink v-if="to" :to="to">
      <!-- 可以点击跳转 -->
      <slot />
    </RouterLink>
    <span v-else>
      <!-- 不可以跳转 -->
      <slot />
    </span>
    <!-- <i class="iconfont icon-angle-right"></i> -->
  </div>
</template>
<script>
export default {
  name: 'XtxBreadItem',
  props: {
    to: {
      // to的值可以是字符串,也可以是对象
      type: [String, Object]
    }
  }
}
</script>

3.全局注册 基于Vue3

// 扩展vue原有的功能:全局组件,自定义指令,挂载原型方法,注意:没有全局过滤器。
// 这就是插件
// vue2.0插件写法要素:导出一个对象,有install函数,默认传入了Vue构造函数,Vue基础之上扩展
// vue3.0插件写法要素:导出一个对象,有install函数,默认传入了app应用实例,app基础之上扩展

    import XtxSkeleton from './skeleton.vue'
    import XtxCarousel from './carousel.vue'
    import XtxMore from './more.vue'
+   import XtxBread from './bread.vue'
+   import XtxBreadItem from './bread-item.vue'

import defaultImg from '@/assets/images/200.png'
const defineDirective = app => {
  // 图片懒加载指令
  app.directive('lazyload', {
    mounted(el, binding) {
      const observer = new IntersectionObserver(
        ([{ isIntersecting }]) => {
          if (isIntersecting) {
            observer.unobserve(el)
            el.onerror = () => {
              el.src = defaultImg
            }
            el.src = binding.value
          }
        },
        {
          threshold: 0.01
        }
      )
      observer.observe(el)
    }
  })
}

export default {
  install(app) {
    // 在app上进行扩展,app提供 component directive 函数
    // 如果要挂载原型 app.config.globalProperties 方式
    app.component(XtxSkeleton.name, XtxSkeleton)
    app.component(XtxCarousel.name, XtxCarousel)
    app.component(XtxMore.name, XtxMore)
 +   app.component(XtxBread.name, XtxBread)
 +   app.component(XtxBreadItem.name, XtxBreadItem)
    defineDirective(app)
  }
}

4.在组件中使用:

 <XtxBread>
      <XtxBreadItem to="/">首页</XtxBreadItem>
      <XtxBreadItem to="/category/1005000">电器</XtxBreadItem>
      <XtxBreadItem>空调</XtxBreadItem>
    </XtxBread>