热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何给一个Vue页面增加纲要导航

一、媒介前两天项目碰到一个须要给页面增加纲要导航的功用,请求把页面中的特定标签加入到纲要导航中。相似如许:需求本身并不难,不过想把这个东西做得通用一些,也就是今后再有别的页面须要加

一、媒介

前两天项目碰到一个须要给页面增加纲要导航的功用,请求把页面中的特定标签加入到纲要导航中。相似如许:

《如何给一个Vue页面增加纲要导航》

需求本身并不难,不过想把这个东西做得通用一些,也就是今后再有别的页面须要加导航,不必再从新写很庞杂的逻辑了。下面说一下详细完成思绪,而且文末会给出轻便易用的导航天生东西。

二、完成思绪

1、需求剖析

做之前想到之前打仗过的markdown编辑器mavon-editor有一个导航,不过谁人导航只能用于编辑器本身,我去看了一下它的表现:

《如何给一个Vue页面增加纲要导航》

点击右侧的导航节点,会自动定位到对应题目元素。当时思索了一下它是怎样纪录题目元素的,会不会是给题目元素加了一个什么id之类的属性?因而我看了一下天生的DOM:

《如何给一个Vue页面增加纲要导航》
居然是给题目元素加了一个带有id属性的a标签的子节点。不过它天生id的体式格局比较简单,纯真的”字符串_编号”罢了,想来并非那末牢靠(难于保证编辑器外有雷同id的元素)。

我大致有了一个基础的思绪:

  • 既然是关于恣意页面都可用,那能够遍历DOM树,寻觅须要导航的标签,然后把相干节点位置信息存储起来。这里也可一相似mavon-editor给dom树中插进去一个元素作为一个锚点。遍历DOM树的要领应当与DOM衬着后从上到下的递次一致,即采纳深度优先的先序遍历要领(先序遍历即先搜检根元素,再搜检子元素;后序遍历则相反;假如是二叉树,另有中序遍历)。
  • 在一切页面中,并不能纯真依据h1,h2等标署名来鉴别一个元素是不是要导航,所以想到了用挑选器来肯定,同时增加依据挑选器来消除一些破例的元素。
  • 终究的导航应当是一个树形构造,而且每个节点对应一个插进去的锚点,即每个树节点应当包括一个锚点信息。

2.完成思绪

由于项目是采纳Vue来完成,数据掌握视图,所以一般不须要直接操纵DOM。然则这里须要在DOM中插进去锚点,Vue自定义指令是一个不错的挑选。因而能够写一个指令,经由过程需求剖析,大致肯定能够这个指令值能够绑定的一个包括以下三个信息的对象:

  • 一个列表selectors:列表中的每一项是一层导航对应的挑选器,比方下标为0的元素是第一级导航,一般能够用挑选器’h1’,下标为1的元素是第二级导航,一般能够用挑选器’h2′;
  • 一个字符串exceptSelector,用于消除破例元素的挑选器;
  • 一个回调函数callback,用于吸收天生的导航树形数据。

三、详细完成

1. 锚点天生函数

须要在每个导航元素邻近位置插进去一个锚点,我这里插在导航元素前面,所以这个函数吸收一个导航元素dom参数,并天生一个元素插进去到dom之前。代码以下:

import uuidv4 from 'uuid/v4'
let ATTR_NAME = 'navigation_anchor'
function createLinkElement (dom) {
let id = uuidv4()
let element = document.createElement('a')
element.setAttribute('id', id)
element.setAttribute(ATTR_NAME, true)
dom.parentNode.insertBefore(element, dom)
return id
}

这个函数吸收导航元素dom作为参数,天生一个a标签,而且给a标签设置了一个uuid(确保唯一性)作为id,同时设置了一个特别属性’navigation_anchor’(尽量庞杂,你以至能够用uuid,不要与DOM中其他元素属性雷同)便于清算一切天生的锚点。

2. 锚点清算函数

用于消灭天生的锚点元素。代码以下:

function clearLinkElement (dom) {
dom = dom || document
let domList = dom.querySelectorAll(`a[${ATTR_NAME}]`)
for (let idx = domList.length - 1; idx > -1; idx--) {
let element = domList[idx]
element.parentNode.removeChild(element)
}
}

能够看到,经由过程给锚点元素设置一个特别属性,在消灭的时刻异常轻易。这里用到一个异常重要的函数querySelectorAll,它会依据挪用的根节点遍历该节点的子DOM树,返回相符某个挑选器的NodeList(一个类数组的对象,但不是数组!),而且遍历体式格局就是上文所述的深度优先先序遍历!真是激动人心!接下来我们能够用这个元素猎取一切须要导航的元素列表。

3. 天生树形导航数据函数

经由过程传入的导航元素DOM根节点、导航元素挑选器列表、导航元素消除挑选器,返回一个树形数据的列表list。查找出一切导航元素,插进去对应锚点,并将锚点信息和导航元素题目存到list中。

function generateNavTree (dom, selectors, exceptSelector) {
clearLinkElement(dom)
let list = []
if (exceptSelector) {
let exceptList = dom.querySelectorAll(exceptSelector)
exceptList.forEach(element => {
element.__nav_except = true
})
}
for (let idx in selectors) {
let elementList = dom.querySelectorAll(selectors[idx])
elementList.forEach(element => {
if (element.__nav_except || element.offsetParent === null) return
element.__nav_level = idx
})
}
let selector = selectors.join(',')
let domList = dom.querySelectorAll(selector)
for (let element of domList) {
if (!element.__nav_level) {
delete element.__nav_except
continue
}
let pushList = list
while (element.__nav_level > 0) {
pushList = pushList.length ? pushList[pushList.length - 1].children : null
if (!pushList) break
element.__nav_level--
}
let data = {
title: element.textContent,
children: [],
id: createLinkElement(element)
}
pushList && pushList.push(data)
delete element.__nav_level
}
return list
}

到这一步有个很有必要注重的处所,导航数据里的title我最最先用了一个超等慢的属性innerText,然后全部页面天生导航(约莫50个导航节点)居然要2s摆布,背面改为了才textContent。经由我的测试,两个属性的接见时候相差n个数量级,接见innerText约莫要30ms,而接见textContent约莫要0.05ms摆布。就是这么大的差异,查阅了相干材料,缘由应当是innerText会引起浏览器重排,耗时超等多。

4. 挪用导航数据天生函数并经由过程回调传给组件。

如今天生导航数据的函数已有了,一个题目就是什么时候挪用此函数呢?我们经由过程Vue指令来完成,能够在响应的钩子函数中挪用。一个机遇是当指令绑定的元素地点模板更新完成之时,另一个机遇是指令绑定元素插进去之时。
指令部份代码以下:

export default {
bind (el, binding, vNode) {
el.__navigatiOnGenerateFunction= () => {
if (el.__generating) return
let selectors = binding.value.selectors || ['h1', 'h2']
let exceptSelector = binding.value.exceptSelector
el.__generating = true
let list = []
generateNavTree(el, selectors, exceptSelector, list)
binding.value.callback(list)
vNode.context.$nextTick(() => {
delete el.__generating
})
}
},
inserted (el, binding, vNode) {
el.__navigationGenerateFunction && el.__navigationGenerateFunction()
},
componentUpdated (el, binding, vNode) {
el.__navigationGenerateFunction && el.__navigationGenerateFunction()
},
unbind (el, binding, vNode) {
clearLinkElement()
if (el.__navigationGenerateFunction) {
delete el.__navigationGenerateFunction
}
}
}

须要注重的是,我们在模板更新完成时插进去锚点元素,而这本身又是会触发模板更新的,所以须要打个标记避死循环。

5. 导航数据的展现

导航数据是一个树形数据,所以能够用树形组件来展现之。比方element或许iview的树组件都能够。不过由于曾对element和iview的树形组件不甚惬意,本身写过一个树形组simple-vue-tree件而且宣布到了npm。
这里我就运用这个组件来展现,下面是一个完全的示例:


四、npm插件

这个导航东西我已宣布到npm了,地点为vue-outline。假如你须要用到而且不想造轮子的话,能够经由过程npm或许yarn等包管理东西装置,而且能够在npm上检察运用要领。

就如许吧,谢谢浏览。第一次在思否写文章,之前一向都在CSDN写博客,不过CSDN太旧了,今后就转到思否吧。


推荐阅读
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 本文详细介绍如何在VSCode中配置自定义代码片段,使其具备与IDEA相似的代码生成快捷键功能。通过具体的Java和HTML代码片段示例,展示配置步骤及效果。 ... [详细]
  • 堆是一种常见的数据结构,广泛应用于计算机科学领域。它通常表示为一棵完全二叉树,并可通过数组实现。堆的主要特性是每个节点的值与其父节点的值之间存在特定的关系,这使得堆在优先队列和排序算法中非常有用。 ... [详细]
  • 本文深入探讨了二叉搜索树(Binary Search Tree, BST)及其操作,包括查找、插入和删除节点。同时,文章还介绍了平衡二叉树(AVL树)的概念及调整方法,并详细讨论了如何判断两个序列是否构成相同的二叉搜索树。 ... [详细]
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • C++实现经典排序算法
    本文详细介绍了七种经典的排序算法及其性能分析。每种算法的平均、最坏和最好情况的时间复杂度、辅助空间需求以及稳定性都被列出,帮助读者全面了解这些排序方法的特点。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文深入探讨了Linux系统中网卡绑定(bonding)的七种工作模式。网卡绑定技术通过将多个物理网卡组合成一个逻辑网卡,实现网络冗余、带宽聚合和负载均衡,在生产环境中广泛应用。文章详细介绍了每种模式的特点、适用场景及配置方法。 ... [详细]
  • 本文详细介绍了Java中org.w3c.dom.Text类的splitText()方法,通过多个代码示例展示了其实际应用。该方法用于将文本节点在指定位置拆分为两个节点,并保持在文档树中。 ... [详细]
  • Codeforces Round #566 (Div. 2) A~F个人题解
    Dashboard-CodeforcesRound#566(Div.2)-CodeforcesA.FillingShapes题意:给你一个的表格,你 ... [详细]
  • 探索电路与系统的起源与发展
    本文回顾了电路与系统的发展历程,从电的早期发现到现代电子器件的应用。文章不仅涵盖了基础理论和关键发明,还探讨了这一学科对计算机、人工智能及物联网等领域的深远影响。 ... [详细]
  • 本题探讨了在一个有向图中,如何根据特定规则将城市划分为若干个区域,使得每个区域内的城市之间能够相互到达,并且划分的区域数量最少。题目提供了时间限制和内存限制,要求在给定的城市和道路信息下,计算出最少需要划分的区域数量。 ... [详细]
  • 本文作者分享了在阿里巴巴获得实习offer的经历,包括五轮面试的详细内容和经验总结。其中四轮为技术面试,一轮为HR面试,涵盖了大量的Java技术和项目实践经验。 ... [详细]
  • 采用IKE方式建立IPsec安全隧道
    一、【组网和实验环境】按如上的接口ip先作配置,再作ipsec的相关配置,配置文本见文章最后本文实验采用的交换机是H3C模拟器,下载地址如 ... [详细]
author-avatar
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有