Vue3从0到1组件开发-布局组件:Breadcrumb面包屑

1,595 阅读3分钟

这是我参与8月更文挑战的第13天,活动详情查看:8月更文挑战

爱丽丝梦游仙境

致爱丽丝

当我们在一条路上走倦了时,总想看看沿途的风景,如果这事突然跑出来穿着西服的兔子,你有勇气跟着他来到那个深不见底树洞旁吗?

当你冲入新世界,在陌生的土地上行走时,记得为沿途的自己做下标记。

回首来时路,亦能见己心。

不整那些有的没的了, 回到面包屑,想必做web开发的小伙伴对这个不会陌生。

而其他的小伙伴可能不知道是啥,但90%肯定是看到过它的。

github举例,这里随便找了个项目截个图,这里的这个小小的导航条记录了访问的一个记录。

就是我们说的面包屑导航拉。

image.png

至于为什么叫面包屑导航,这就又是另一个故事《汉赛尔和格莱特》了。

tips-1: 为什么标题是爱丽丝呢,因为我喜欢她啊。

tips-2: 童话故事里,黑心的后母把汉赛尔和格莱特带到森林里,等他们睡着后离去,让他们迷失在森林里,而聪明的韩赛尔在来时路上洒落了捏碎的面包屑,靠着他们找到了回去的路。

所以面包屑导航的作用也很清楚拉, 确认当前的位置, 以及帮助跳转到之前的界面中。

分析一下

通过上面的tips-2故事梗概可以看出, 面包屑导航的主要作用在于记录一段访问记录,而这时有一点需要注意,平级跳转应该是替换当前导航,而不是新增下一级导航。当然这是开发时需要注意的,组件开发过程中可以忽略。

那么去除掉平级替换这件事的话, 主要的难点是什么呢?其实没啥难点, 无非是处理下当前页面还是新页面打开。

当然,如果想处理的话,可以是否替换当前层级的路由也写进组件里, 一个参数+一个函数就能搞定。 但是这种比较偏向于业务组件了,后面将业务组件时会二次封装处理这一点。

开始搞它

首先还是从结构说起。

父级结构还是搭台子,就是丢个容器就完事了。

block content
div.yx-breadcrumb
  slot

主要的内容部分当然是交给子级结构来处理了。主要是渲染一个显示的样式。

block content
span
  a(
    v-if="to"
    :href="url"
    :target="target"
    class="yx-breadcrumb-item-link"
    @click.exact="handleCheckClick($event,false)" // 仅点击时
    @click.ctrl="handleCheckClick($event, true)"  // ctrl + 单击
    @click.meta="handleCheckClick($event, true)"  // meta + 单击
  )
    slot
  span(v-else class="yx-breadcrumb-item-link")
    slot
  span(v-html="separator" v-if="!showSeparator" class="yx-breadcrumb-item-separator")
  span(class="yx-breadcrumb-item-separator" v-else)
    slot

image.png

分别是默认效果,鼠标经过效果, 当前页。

这里的separator就是中间的间隔符,用户传值props传值给父级,父级通过ctx.$children[{index}].separator = props.separator; 传递给自己。

逻辑部分

逻辑部分其实也比较简单啦。

主要是点击事,判断打开方式, 按住windows+点击 或者 Macos系统的meta键+单击则在新的界面打开,否则的话,根据传值来判断是否在当前页打开。

const handleClick = (new_window = false) => {
  const router = ctx.$router;

  if (new_window) {
    let to = props.to;
    if (router) {
      const current = ctx.$route;
      const route = router.resolve(props.to, current, props.append);
      to = route ? route.href : props.to;
    }
    window.open(to);
  } else {
      if (router) {
          props.replace ? ctx.$router.replace(props.to, () => {}) : ctx.$router.push(props.to, () => {});
      } else {
          window.location.href = props.to;
      }
  }
}

const handleCheckClick = (event, new_window = false) => {
  if (props.to) {
    if (props.target === '_blank') {
      return false;
    } else {
      event.preventDefault();
      handleClick(new_window);
    }
  }
}

其他的就没啥了,如果非要有啥的话,就是根据业务需求去进行对应的修改了。

总结

这个组件也是比较简单的一个组件了。但是在大部分的web界面中是很比较实用,有需求的小伙伴可以动动脑筋修改出自己的组件。

回首来时路,总能在沿途看到自己曾经留下的“面包屑”。