<script src="https://cdn.jsdelivr.net/gh/yaohaixiao/outline.js/outline.min.js"></script>

Options

outline.js 有者丰富的配置选项,以便适应不同的展示方式。

articleElement

Description

Type:
String|HTMLElement
Default:
'#article'
  • String:选择器字符串,默认值:html,body(即 window 窗口);
  • HTMLElement:'DOM 元素;

可选,用来指定页面中显示文章正文的 DOM 节点或者选择器字符串。

// Default Selector
const outline = new Outline(Outline.DEFAULTS)

// Customize Selector
const outline = new Outline({
  articleElement: $('#main')
})

selector

Description

Type:
String
Default:
'h1,h2,h3,h4,h5,h6'

可选,用来指定 article 节点下,要生成导航的标题标签的选择器。

// Default selector
new Outline(Outline.DEFAULTS)

// Customize selector
new Outline({
  selector: 'h2'
})

title

Description

Type:
String|Boolean
Default:
'目录'

可选,用来指定文章导读导航菜单的标题文字。设置空字符串或者 false,则不显示标题。在插入导航菜单的 DOM 元素已有标题时,可以设置 title: '' 或者 false。

说明:本 API 文档的导航菜单便是使用 outline.js 生成,并且没有设置 title。

(function(){
  const defaults = Outline.DEFAULTS
  let outline

  defaults.selector = 'h2,h3'
  defaults.title = ''
  defaults.showCode = false
  defaults.position = 'sticky'
  defaults.parentElement = '#aside'
  defaults.scrollElement = '#main'
  defaults.articleElement = '#article'
  defaults.homepage = './index.html'
  defaults.git = 'https://github.com/yaohaixiao/outline.js'
  defaults.tags = 'https://github.com/yaohaixiao/outline.js/tags'
  defaults.issues = 'https://github.com/yaohaixiao/outline.js/issues'
  defaults.print = {
    element: '#article',
    title: 'Outline.js'
  }
  outline = new Outline(Outline.DEFAULTS)
})()

scrollElement

Description

Type:
String|HTMLElement
Default:
'html,body'
  • String: 选择器字符串,默认值:html,body(即 window 窗口);
  • HTMLElement: DOM 元素;

可选,负责文章区域滚动的元素:

// 默认是当前窗口滚动
new Outline(Outline.DEFAULTS)

// 指定滚动区域是 #main 元素
new Outline({
  scrollElement: '#main'
})

position

Description

Type:
String
Default:
'relative'

可选,用来指定文章导读导航菜单的显示位置:

  • relative: (默认值)创建独立的侧滑菜单;
  • sticky: 导航菜单将以 sticky 模式布局(需要确保菜单插入位置(DOM 节点)支持 sticky 模式布局);
  • fixed: 导航菜单将模拟 sticky 布局,起初是普通定位,会自动监听滚动位置,但滚动到导航菜单顶部时,以 fixed 模式布局,模拟 sticky 布局效果;

当设置为 sticky 和 fixed 布局时,需要设置 parentElement。

注意:2.0.0 暂时不支持之前版本那种 inside 模式,不会自动在文章开始位置插入 chapters 导航菜单

// 默认生成独立的侧滑弹窗导航菜单
new Outline(Outline.DEFAULTS)

// 在页面内部插入导航菜单
new Outline({
  // 在(文章的)侧边栏显示导航菜单
  parentElement: '#aside',
  // 或者 sticky 定位
  position: 'fixed'
})

parentElement

Description

Type:
String
Default:
'#aside'
  • String: 选择器字符串,默认值:html,body(即 window 窗口);
  • HTMLElement: DOM 元素;

可选,导航菜单将要插入的位置(DOM 元素)。仅在 position 设置为 sticky 和 fixed 布局时有效。

// 在页面内部插入导航菜单
new Outline({
  // 在(文章的)侧边栏显示导航菜单
  parentElement: '#aside',
  // 或者 sticky 定位
  position: 'fixed'
})

placement

Description

Type:
String
Default:
'rtl'

可选,设置 position: relative 时,placement 定义侧滑菜单和 toolbar 导航位置:

  • rtl - 菜单位置在窗口右侧,滑动动画为:right to left(默认值);
  • ltr - 菜单位置在窗口左侧,滑动动画为:left to right;
  • ttb - 菜单位置在窗口上方,滑动动画为:top to bottom;
  • btt - 菜单位置在窗口下方,滑动动画为:bottom to top;
// 默认是在窗口右侧显示侧滑导航菜单
new Outline(Outline.DEFAULTS)

// 调整为在窗口右侧显示侧滑导航菜单
new Outline({
  placement: 'ltr'
})

stickyHeight

Description

Type:
Number
Default:
0

可选,用来指定页面中其它 sticky 或者模拟 skicky 的 fiexed 定位的 DOM 元素的高度。

这些 sticky 元素脱离了正常的流布局后,原来 h1~h6 标题标签的 offsetTop 计算会出现偏差。sticky 元素会遮挡标题,因此针对页面中有其它sticky 节点时,需要设置 stickyHeight 高度。以便 outline.js 根据 stickyHeight 和计算出的标题的 offsetTop 值重新计算滚动定位。

说明:outline.js 主要用于文章详情页面,stickyHeight 仅针对 top: 0,且 sticky 定位元素在文章内容区域上方的位置;

const defaults = Outline.DEFAULTS

// 设置 stickyHeight(outline.js 的示例页面的主标题元素的高度)
defaults.stickyHeight = 86
// 默认生成独立的侧滑弹窗导航菜单
new Outline(defaults)

showCode

Description

Type:
Boolean
Default:
true

可选,是否显示段落章节编号:

  • true - 显示编号(默认值);
  • false - 不显示编号;

animationCurrent

Description

Type:
Boolean
Default:
true

可选,是否采用动画定位高亮当前的章节标题:

  • true - 采用动画定位高亮(默认值);
  • false - 采用高亮当前章节标题的链接文字并加粗文字;

hasToolbar

Description

Type:
Boolean
Default:
true

可选,是否显示侧边的按钮工具栏:

  • true - 显示按钮工具栏(默认值);
  • false - 不显示按钮工具栏;

anchorURL

Description

Type:
String
Default:
''

可选,用来指定文章标题锚点链接图标的链接地址:

// Default URL - 默认链接,点击图标,页面会滚动到当前标题位置
new Outline()

// Customize URL - 直接打开链接了
new Outline({
  anchorURL: 'http://www.yaohaixiao.com/'
})

homepage

Description

Type:
String
Default:
''

可选,用来指定文章标题锚点链接图标的链接地址:

const outline = new Outline(Outline.DEFAULTS)

// 侧边栏的 Toolbar 会多出一个 Homepage 图标的按钮
outline.reload({
  homepage: 'http://www.yaohaixiao.com/'
})

git

Description

Type:
String
Default:
''

可选,针对 API 文档类的文章页面,指定项目 git 仓库地址:

const outline = new Outline(Outline.DEFAULTS)

// 侧边栏的 Toolbar 会多出一个 git 图标的按钮
outline.reload({
  git: 'https://github.com/yaohaixiao/outline.js'
})

tags

Description

Type:
String
Default:
''

可选,针对 API 文档类的文章页面,指定项目 git 仓库 tags 页面地址:

const outline = new Outline(Outline.DEFAULTS)

// 侧边栏的 Toolbar 会多出一个 tags 图标的按钮
outline.reload({
  tags: 'https://github.com/yaohaixiao/outline.js/tags'
})

issues

Description

Type:
String
Default:
''

可选,针对 API 文档类的文章页面,指定项目 git 仓库 issues 页面地址:

const outline = new Outline(Outline.DEFAULTS)

// 侧边栏的 Toolbar 会多出一个 issues 图标的按钮
outline.reload({
  issues: 'https://github.com/yaohaixiao/outline.js/issues'
})

tools

Description

Type:
Array
Default:
[]

可选,自定义的按钮配置项。tools 中的按钮会排列显示在 homepage, git, tags, issues 等按钮之后。

const outline = new Outline(Outline.DEFAULTS)
// 如果需要其它图标,可以到 https://github.com/yaohaixiao/icons.toolkit.vue 项目中选择需要的图标资源
const clean = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 1024 1024">' +
  '<path d="M704 32V320h288a32 32 0 0 1 32 32v320a32 32 0 0 1-32 32H32a32 32 0 0 1-32-32v-320A32 32 0 0 1 32 320H320V32a32 32 0 0 1 32-32h320a32 32 0 0 1 32 32zM576 128H448v320H128v128h768V448H576V128z"></path>' +
  '<path d="M896 576v416a32 32 0 0 1-32 32h-704a32 32 0 0 1-32-32V576h768z m-128 128H256v192h512v-192z"></path>' +
  '</svg>'

// 侧边栏的 Toolbar 会多出一个 git 图标的按钮
outline.reload({
  git: 'https://github.com/yaohaixiao/outline.js',
  tools: [
    {
      name: 'clean',
      // 图标
      icon: clean,
      size: 20,
      color: '#f00'
      // link 指定按钮点击后页面的跳转地址
      link: 'https://github.com/yaohaixiao',
      // link 和 action 只能二选一
      // action 指定按钮的处理方式
      action: {
        type: 'click',
        // 指定回调函数的 this 上下文,不设置 this 指向 toolbar 组件
        context: outline,
        handler: function() {
          // 回调函数的处理逻辑
        }
      }
    }
  ]
})

print

Description

Type:
Object
Default:
{element: '', title: ''}

可选,自定义的是否自动为文章页面创建打印样式。

element:
(必须)要打印的文章区域,DOM 元素或者选择器字符串。
title:
(可选)要打印的文章标题。如果 element 区域有 h1 标签则无需设置。可以直接设置标题文本,也可以是文章页的主标题 DOM 元素。
const defaults = Outline.DEFAULTS
let outline

defaults.position = 'sticky'
defaults.stickyHeight = 86
defaults.parentElement = '#aside'
defaults.scrollElement = '#main'
defaults.homepage = './index.html'
defaults.git = 'https://github.com/yaohaixiao/outline.js'
defaults.tags = 'https://github.com/yaohaixiao/outline.js/tags'
defaults.issues = 'https://github.com/yaohaixiao/outline.js/issues'
defaults.print = {
  element: '#article',
  // 可以直接设置标题文本,也可以是文章页的主标题 DOM 元素。
  // 纯静态的页面,设置 DOM 元素,可能更好,确保每个页面的主标题 DOM 元素的选择器不变
  // 则 title 会是一个可变的值,这样比直接设置标题文本更加灵活;
  title: document.querySelector('.title'),
  // 进入阅读模式的提示消息文本
  enterReadingTip: '进入阅读模式,按 ESC 键可退出阅读模式'
}
outline = new Outline(Outline.DEFAULTS)

演示地址:https://yaohaixiao.github.io/outline.js/flex.html

customClass

Description

Type:
String
Default:
''

可选,(DIYer福利)设置自定义样式的 class 名称:

  • '' - 采用默认 outline.js 的 UI 界面(默认值);
  • 设置自定义样式 - 自己根据需求设置个性化的 UI 界面;
// Default UI
new Outline(Outline.DEFAULTS)

// Customized
new Outline({
  // 设置深色配置界面
  customClass: 'theme-dark'
})

afterScroll

Description

Type:
Function
Default:
null

可选,当点击导航菜单、文章中的 anchor 图标(#)或者上下滚动按钮会触发滚动,afterScroll() 回调函数会在滚动结束后触发执行。

Parameters

target
Type:
String

afterScroll() 回调函数有一个参数 target,返回的是当前点击的 DOM 元素的名称:

  • 'anchor':表示点击的是 anchor 图标,即文章中标题前的 “#” 图标,此时的 this 上下文指向 outline.anchors;
  • 'chapter':表示点击的是导航菜单的链接,此时的 this 上下文指向 outline.chapters;
  • 'up':表示点击的是工具栏的向上按钮,此时的 this 上下文指向 outline.toolbar;
  • 'down':表示点击的是工具栏的向下按钮,此时的 this 上下文指向 outline.toolbar;

注意:因为配置 afterScroll 回调函数会因为 4 个不同的 DOM 触发,所以需要根据 target 返回的值和此时的 this 指向判断处理。

const defaults = Outline.DEFAULTS
let outline

defaults.position = 'fixed'
defaults.parentElement = '#aside'
defaults.stickyHeight = 86
defaults.homepage = './index.html'
defaults.afterScroll = function(target) {
  // 当然,如果你希望无论是点击什么都执行,就不需要判断了
  // 直接些通用的滚动结束的逻辑即可
  switch(target){
    case 'anchor':
      // 针对点击 # 的处理逻辑
      break
    case 'chapter':
      // 针对点击导航菜单的处理逻辑
      break
    case 'up':
      // 针对点击向上滚动按钮的处理逻辑
      break
    case 'down':
      // 针对点击向下滚动按钮的处理逻辑
      break
  }
}
outline = new Outline(Outline.DEFAULTS)

afterSticky

Description

Type:
Function
Default:
null

可选,在设置 position: fixed 时,当导航菜单样式为 fixed 获取恢复为普通定位的时候,会触发执行 afterSticky 回调函数。

说明:afterSticky() 回调函数的 this 上下文执行 outline.chapters 对象。

Parameters

closed
Type:
Boolean

closed 参数值为 true 表示菜单处于隐藏状态,否则表示菜单处于显示状态

isSticky
Type:
Boolean

isSticky 参数值为 true 表示(position:fixed)菜单处于模拟 sticky 定位(position:fixed)状态,否则表示菜单处于普通状态。

const $header = document.querySelector('#header')
const HEADER_STICKY = 'header_sticky'
const defaults = Outline.DEFAULTS
let outline

defaults.position = 'fixed'
defaults.parentElement = '#aside'
defaults.stickyHeight = 86
defaults.homepage = './index.html'
defaults.afterSticky = function(closed, isStickying) {
  const $nav = this.$el
  const BORDER_RIGHT = 'utils-border-right'

  if (closed) {
    return false
  }

  if (isStickying) {
    $nav.classList.add(BORDER_RIGHT)
    $header.classList.add(HEADER_STICKY)
  } else {
    $nav.classList.remove(BORDER_RIGHT)
    $header.classList.remove(HEADER_STICKY)
  }
}
defaults.afterToggle = function(closed, isStickying) {
  if (!isStickying) {
    return false
  }

  if (closed) {
    $header.classList.remove(HEADER_STICKY)
  } else {
    $header.classList.add(HEADER_STICKY)
  }
}
outline = new Outline(Outline.DEFAULTS)

afterToggle

Description

Type:
Function
Default:
null

可选,当导航菜单隐藏或者显示的时候,会触发执行 afterToggle 回调函数。

说明:afterSticky() 回调函数的 this 上下文执行 outline.chapters 对象。

Parameters

closed
Type:
Boolean

closed 参数值为 true 表示菜单处于隐藏状态,否则表示菜单处于显示状态

isSticky
Type:
Boolean

isSticky 参数值为 true 表示(position:fixed)菜单处于模拟 sticky 定位(position:fixed)状态,否则表示菜单处于普通状态。

const $header = document.querySelector('#header')
const HEADER_STICKY = 'header_sticky'
const defaults = Outline.DEFAULTS
let outline

defaults.position = 'fixed'
defaults.parentElement = '#aside'
defaults.stickyHeight = 86
defaults.homepage = './index.html'
defaults.afterSticky = function(closed, isStickying) {
  const $nav = this.$el
  const BORDER_RIGHT = 'utils-border-right'

  if (closed) {
    return false
  }

  if (isStickying) {
    $nav.classList.add(BORDER_RIGHT)
    $header.classList.add(HEADER_STICKY)
  } else {
    $nav.classList.remove(BORDER_RIGHT)
    $header.classList.remove(HEADER_STICKY)
  }
}
defaults.afterToggle = function(closed, isStickying) {
  if (!isStickying) {
    return false
  }

  if (closed) {
    $header.classList.remove(HEADER_STICKY)
  } else {
    $header.classList.add(HEADER_STICKY)
  }
}
outline = new Outline(Outline.DEFAULTS)

chapterTextFilter

Description

Type:
Function
Default:
null

可选,API 文档中,正文的方法会添加参数等信息,例如:getChapters(headings, showCode, chapterTextFilter)。而在 chapters 导航菜单,我希望显示为 getChapters(),这时我们就可以借助 chapterTextFilter 回调函数。对原始的文本进行过滤,返回我们期望的 getChapters() 文本。

Parameters

text
Type:
String

chapterTextFilter() 回调函数有一个参数 text,返回的是当前 hx 标题中的文本。

const defaults = Outline.DEFAULTS
let outline

defaults.selector = 'h2,h3'
defaults.title = false
defaults.showCode = false
defaults.position = 'sticky'
defaults.parentElement = '#aside'
defaults.scrollElement = '#main'
defaults.articleElement = '#article'
defaults.homepage = './index.html'
defaults.git = 'https://github.com/yaohaixiao/outline.js'
defaults.tags = 'https://github.com/yaohaixiao/outline.js/tags'
defaults.issues = 'https://github.com/yaohaixiao/outline.js/issues'
defaults.print = {
  element: '#article',
  title: 'Outline.js'
}
defaults.chapterTextFilter = (text) => {
  return text.replace(/\(.*?\)/, '()')
}
outline = new Outline(Outline.DEFAULTS)

Properties

outline.js 重构后,对外放 4 个重要的属性:anchors、drawer、chapters 和 toolbar。它们都是独立的对象实例,提供了 outline.js 所有的能力(属性和方法)。

attrs

Description

Type:
Object

存储的是 Outline 对象当前使用中的配置选项:

说明:建议使用 attr(prop) 方法来获取属性,避免直接调用属性。

// 设置默认配置项
const outline = new Outline(Outline.DEFAULTS)

// 查看全部配置信息
outline.attrs

buttons

Description

Type:
Array

存储的是 Outline 对象当前工具栏的完整的按钮配置信息:

// 设置默认配置项
const outline = new Outline(Outline.DEFAULTS)

// 查看全部按钮配置信息
outline.buttons

anchors

Description

Type:
Object

Anchors 模块:类似 AnchorJS 基础功能模块,自动分析段落层级。

// 仅展示 API 中对外公开的方法和属性
class Anchors extends Base {
  constructor(options) {
    super()

    this.attrs = Anchors.DEFAULTS
    this.$articleElement = null
    this.$scrollElement = null
    this.$headings = []
    this.chapters = []

    // 省略其它逻辑...
  }

  getChapters(isTreeStructured = false) {
    const chapters = this.chapters
    return isTreeStructured ? toTree(chapters, 'id', 'pid') : chapters
  }

  count() {
    return this.chapters.length
  }

  attr(prop, value) {
    const attrs = this.attrs

    if (isString(prop)) {
      // 只能扩展 attrs 中已有的属性
      if (value && hasOwn(attrs, prop)) {
        // 更新单个配置信息
        attrs[prop] = value
        return this
      }

      // 只传递 prop 参数,则返回对应的属性值
      return attrs[prop]
    } else if (isObject(prop)) {
      // 批量更新配置信息
      extend(attrs, prop)

      return this
    } else if (arguments.length === 0) {
      // 不传递参数,直接返回整个
      return attrs
    }

    return this
  }

  render() {
    // 省略其它逻辑...
    return this
  }

  scrollTo(top, after) {
    // 省略其它逻辑...
    return this
  }

  destroy() {
    this.removeListeners()
    // 省略其它逻辑...
    return this
  }

  reload(options) {
    this.destroy().initialize(this.attr(options))
    return this
  }
}

Anchors.DEFAULTS = {
  scrollElement: 'html,body',
  articleElement: '#article',
  selector: 'h1,h2,h3,h4,h5,h6',
  anchorURL: '',
  hasAnchor: true,
  isAtStart: true,
  showCode: false,
  created: null,
  mounted: null,
  afterScroll: null,
  beforeDestroy: null,
  afterDestroy: null
}

export default Anchors

chapters

Description

Type:
Object

Chapters 模块:独立的导航菜单模块;

// 仅展示 API 中对外公开的方法和属性
class Chapters extends Base {
  constructor(options) {
    super()

    this.attrs = Chapters.DEFAULTS
    this.$el = null
    this.$title = null
    this.$main = null
    this.$list = null
    this.$placeholder = null
    this.$parentElement = null
    this.$scrollElement = null
    this.chapters = []
    this.closed = false
    this.active = 0
    this.offsetTop = 0
    this.$active = null
    this.timer = null
    this.playing = false

    // 省略其它逻辑...
  }

  isClosed() {
      return this.closed
  }

  isSticky() {
    const position = this.attr('position')
    return position === 'sticky'
  }

  isFixed() {
    const position = this.attr('position')
    return position === 'fixed'
  }

  isInside() {
    return this.isFixed() || this.isSticky()
  }

  isOutside() {
    return !this.isInside()
  }

  attr(prop, value) {
    // 省略其它逻辑...
    return this
  }

  render() {
    // 省略其它逻辑...
    return this
  }

  highlight(id) {
    // 省略其它逻辑...
    return this
  }

  sticky() {
    // 省略其它逻辑...
    return this
  }

  scrollTo(top, after) {
    // 省略其它逻辑...
    return this
  }

  show() {
    // 省略其它逻辑...
    return this
  }

  hide() {
    // 省略其它逻辑...
    return this
  }

  toggle() {
    // 省略其它逻辑...
    return this
  }

  destroy() {
    this.removeListeners()
    // 省略其它逻辑...
    return this
  }

  reload(options) {
    this.destroy().initialize(this.attr(options))
    return this
  }
}

Chapters.DEFAULTS = {
  parentElement: '',
  scrollElement: '',
  selector: '',
  active: 0,
  closed: false,
  showCode: true,
  position: 'relative',
  chapters: [],
  created: null,
  mounted: null,
  afterClosed: null,
  afterOpened: null,
  afterScroll: null,
  beforeDestroy: null,
  afterDestroy: null
}

export default Chapters

drawer

Description

Type:
Object

Drawer 模块:独立的侧滑窗口模块。

// 仅展示 API 中对外公开的方法和属性
class Drawer extends Base {
  constructor(options) {
    super()

    this.attrs = Drawer.DEFAULTS
    this.title = ''
    this.closed = true
    this.$el = null
    this.$modal = null
    this.$header = null
    this.$title = null
    this.$close = null
    this.$main = null
    this.$footer = null
    this.$overlay = null
    this.zIndex = 0

    // 省略其它逻辑...
  }

  isClosed() {
      return this.closed
  }

  setTitle() {
    this.attr('title', title)
    this.title = title
    this.$title.innerHTML = title

    return this
  }

  attr(prop, value) {
    // 省略其它逻辑...
    return this
  }

  render() {
    // 省略其它逻辑...
    return this
  }

  open() {
    // 省略其它逻辑...
    return this
  }

  close() {
    // 省略其它逻辑...
    return this
  }

  toggle() {
    // 省略其它逻辑...
    return this
  }

  destroy() {
    this.removeListeners()
    // 省略其它逻辑...
    return this
  }

  reload(options) {
    this.destroy().initialize(this.attr(options))
    return this
  }
}

Drawer.DEFAULTS = {
   placement: 'rtl',
   title: '标题',
   size: 'regular',
   hasClose: true,
   hasOverlay: true,
   hasOffset: false,
   hasPadding: true,
   created: null,
   mounted: null,
   afterClosed: null,
   afterOpened: null,
   afterScroll: null,
   beforeDestroy: null,
   afterDestroy: null
}

export default Drawer

toolbar

Description

Type:
Object

Toolbar 模块:独立的固定定位的工具栏模块;

// 仅展示 API 中对外公开的方法和属性
class Toolbar extends Base {
  constructor(options) {
    super()

    this.attrs = Drawer.DEFAULTS
    this.title = ''
    this.closed = true
    this.$el = null
    this.$modal = null
    this.$header = null
    this.$title = null
    this.$close = null
    this.$main = null
    this.$footer = null
    this.$overlay = null

    // 省略其它逻辑...
  }

  isDisabled(name) {
    const buttons = this.attr('buttons')
    let button

    if (name) {
      button = buttons.find((option) => option.name === name)

      return !!(button && button.disabled)
    }

    return this.disabled
  }

  isClosed() {
    return this.closed
  }

  highlight() {
    // 省略其它逻辑...
    return this
  }

  attr(prop, value) {
    // 省略其它逻辑...
    return this
  }

  render() {
    // 省略其它逻辑...
    return this
  }

  add(button) {
    // 省略其它逻辑...
    return this
  }

  remove(name) {
    // 省略其它逻辑...
    return this
  }

  switch(name, enabled) {
    // 省略其它逻辑...
    return this
  }

  enable(name) {
    // 省略其它逻辑...
    return this
  }

  disable(name) {
    // 省略其它逻辑...
    return this
  }

  show() {
    // 省略其它逻辑...
    return this
  }

  hide() {
    // 省略其它逻辑...
    return this
  }

  toggle() {
    // 省略其它逻辑...
    return this
  }

  destroy() {
    this.removeListeners()
    // 省略其它逻辑...
    return this
  }

  reload(options) {
    this.destroy().initialize(this.attr(options))
    return this
  }
}

Toolbar.DEFAULTS = {
   placement: 'ltr',
   closed: false,
   disabled: false,
   buttons: [],
   created: null,
   mounted: null,
   afterClosed: null,
   afterOpened: null,
   afterDisabled: null,
   afterEnabled: null,
   beforeDestroy: null,
   afterDestroy: null
}

Drawer.zIndex = 2000

export default Toolbar

Outline.DEFAULTS

Description

Type:
Object

静态属性,存储的是 Outline 对象默认配置选项:

Outline.DEFAULTS = {
  // 文章显示区域的 DOM 元素或者选择器字符串
  articleElement: '#article',
  // 要收集的标题选择器
  selector: 'h2,h3,h4,h5,h6',
  // 指定文章导读导航菜单的标题文字。
  // 设置空字符串或者 false,则不显示标题
  // 在插入导航菜单的 DOM 元素已有标题时,可以设置 title: '' 或者 false
  title: '目录',
  // 负责文章区域滚动的元素
  // String 类型 - 选择器字符串,默认值:html,body(window窗口)
  // HTMLElement 类型 - DOM 元素
  scrollElement: 'html,body',
  // 文章导读菜单的位置
  // relative - (默认值)创建独立的侧滑菜单
  // sticky - 导航菜单将以 sticky 模式布局(需要确保菜单插入位置支持 sticky 模式布局)
  // fixed - 导航菜单将以 fixed 模式布局,会自动监听滚动位置,模拟 sticky 布局
  // sticky 和 fixed 布局时,需要设置 parentElement
  // 2.0.0 暂时不支持之前版本那种 inside 模式,不会自动在文章开始位置插入 chapters 导航菜单
  position: 'sticky',
  // 导航菜单将要插入的位置(DOM 元素)
  // String 类型 - 选择器字符串
  // HTMLElement 类型 - 插入的 DOM 元素
  // 仅在 position 设置为 sticky 和 fixed 布局时有效
  parentElement: '#aside',
  // 设置 position: relative 时,placment 定义侧滑菜单和 toolbar 导航位置:
  // rtl - 菜单位置在窗口右侧,滑动动画为:right to left
  // ltr - 菜单位置在窗口左侧,滑动动画为:left to right
  // ttb - 菜单位置在窗口上方,滑动动画为:top to bottom
  // btt - 菜单位置在窗口下方,滑动动画为:bottom to top
  placement: 'rtl',
  // 页面中其它 sticky 或者模拟 skicky 的 fiexed 定位的 DOM 元素的高度。例如 wordpress 系统中,
  // 就会有 sticky 定位的导航菜单。这些 sticky 元素脱离了正常的流布局后,原来 h1~h6 标题标签的
  // offsetTop 计算会出现偏差。sticky 元素会遮挡标题,因此针对页面中有其它 sticky 元素会遮挡标题,
  // 因此针对 sticky 布局时,需要设置 stickyHeight 高度。outline.js 会根据 stickyHeight 和计
  // 算出的标题的 offsetTop 值重新计算滚动定位;
  // 说明:outline.js 主要用于文章详情页面,
  // 因此 stickyHeight 仅针对 top: 0,且 sticky 定位元素在文章内容区域上方的位置;
  stickyHeight: 0,
  // 是否显示标题编号
  showCode: true,
  // 是否显示侧边的按钮工具栏
  hasToolbar: true,
  // 指定是否采用动画定位高亮当前的章节标题,默认值:true
  // 当值为 false 时,则采用高亮当前章节标题的链接文字并加粗文字
  // 如果喜欢更简洁的高亮效果,可以选择设置为 false
  animationCurrent: true,
  // 标题图标链接的 URL 地址
  // (默认)没有设置定制,点击链接页面滚动到标题位置
  // 设置了链接地址,则不会滚动定位
  anchorURL: '',
  // 指定当前站点主页地址
  homepage: '',
  // 指定git仓库地址
  git: '',
  // 指定git仓库中的 tags 地址
  tags: '',
  // 指定git仓库中的 issues 地址
  issues: '',
  // 自定义按钮配置
  tools: [],
  // 为文章页添加基础的打印样式
  // 如果您的页面已经有打印样式,就无需设置了
  print: {
    //(必须)要打印的文章区域,DOM 元素或者选择器字符串。
    element: '',
    // (可选)要打印的文章标题。如果 element 区域有 h1 标签则无需设置。
    // 可以直接设置标题文本,也可以是文章页的主标题 DOM 元素
    title: '',
    // 进入阅读模式的提示消息文本
    enterReadingTip: '进入阅读模式,按 ESC 键可退出阅读模式'
  },
  // DIYer的福利
  // 独立侧滑菜单时,customClass 会追加到 drawer 侧滑窗口组件
  // 在文章中显示导航菜单时,customClass 会追加到 chapters 导航菜单
  customClass,
  // position: fixed,当导航菜单样式进入 fixed 定位后,触发的回调函数
  afterSticky: null,
  // 当导航菜单隐藏或者显示后,触发的回调函数
  afterToggle: null,
  // 当点击上下滚动按钮,导航菜单或者文章中的 # 图标,滚动结束后触发的回调函数
  afterScroll: null,
  // 文档的标题文本过滤回调函数
  // API 文档中,正文的方法会添加参数等信息,例如:getChapters(headings, showCode, chapterTextFilter)
  // 而在 chapters 导航菜单,我希望显示为 getChapters(),这时我们就可以借助 chapterTextFilter 回调函数
  // 对原始的文本进行过滤,返回我们期望的 getChapters() 文本
  chapterTextFilter: null
}

Methods

outline.js 的提供的方法如下:

attr([prop, value])

Description

attr() 方法用来设置或者获取初始化时配置的 attrs 信息的。

Parameters

prop
Type:
String|HTMLElement

(可选)options 中的属性名称或者要配置的 attrs 信息。

value
Type:
Any

(可选)要设置的 prop 属性的值

  • 不传递任何参数:返回完整的 attrs 配置信息;
  • 仅传递 prop:
    • String: 返回 attrs 配型信息中与 prop 对应的值;
    • Object: 用来设置 attrs 配置信息;
  • 同时传递 prop 和 value 参数:设置 attrs 配置信息中的某个属性值;

Returns

Type:
Any

配置信息 attrs 的属性值或者 Outline 对象。

const outline = new Outline({
   article: '#article',
   title: 'Outline v2.0.0'
})

outline.attr('title') // -> 'Outline v2.0.0'
outline.attr('title', '目录') // -> 设置 title 配置信息的值为 '目录'
outline.attr() // -> 返回完整配置参数 attrs 信息

getChapters([isTreeStructured])

Description

getChapters() 方法来获取 outline.js 分析的文章段落层次数据。

Parameters

isTreeStructured
Type:
Boolean
Default:
false

(可选)是否为树结构的数据。

  • false: (默认值)输出打平的一维数组格式数据;
  • true: 输出树结构格式的数据;

Returns

Type:
Object

outline.js 分析的文章段落层次数据。

const outline = new Outline({
   article: '#article',
   title: 'Outline v2.0.0'
})

outline.getChapters()
// 一维数组格式数据
// -> [{
  {
    id: 2,
    pid: -1,
    level: 1,
    rel: "heading-2",
    text: "安装说明",
    index: 3,
    code: "3",
  },
  {
    id: 3,
    pid: 2,
    level: 2,
    rel: "heading-3",
    text: "npm install",
    index: 1,
    code: "3.1",
    children: []
  },
  {
    id: 4,
    pid: 2,
    level: 2,
    rel: "heading-4",
    text: "CDN 调用",
    index: 2,
    code: "3.2",
    children: []
  },
  {
    id: 5,
    pid: 2,
    level: 2,
    rel: "heading-5",
    text: "调用本地JS文件",
    index: 3,
    code: "3.3",
    children: []
  }
}]

outline.getChapters(true)
// 有 children 属性的树结构对象数组
// -> [{
  code: "3",
  id: 2,
  index:3,
  level:1,
  pid:-1,
  rel: "heading-2"
  text:"安装说明",
  children: [
    {
      id: 3,
      pid: 2,
      level: 2,
      rel: "heading-3",
      text: "npm install",
      index: 1,
      code: "3.1",
      children: []
    },
    {
      id: 4,
      pid: 2,
      level: 2,
      rel: "heading-4",
      text: "CDN 调用",
      index: 2,
      code: "3.2",
      children: []
    },
    {
      id: 5,
      pid: 2,
      level: 2,
      rel: "heading-5",
      text: "调用本地JS文件",
      index: 3,
      code: "3.3",
      children: []
    }
  ]
}]


outline.destroy()
outline.getChapters()
// 调用 destroy() 方法后,所有数据都清空了
// -> []

count()

Description

count() 方法来获取 outline.js 分析的文章段落层次数据的数量。

Returns

Type:
Number

outline.js 分析的 chapters 数据数量。

const outline = new Outline({
   article: '#article',
   title: 'Outline v2.0.0'
})

outline.getChapters()
// -> [{
  code: "1",
  id: 0,
  index: 1,
  level: 1,
  pid: -1
  rel: "heading-0"
  text: "创作灵感"
}]

outline.count()
// -> 1 就是 getChapters() 返回数据的数量

addButton(button)

Description

addButton() 方法添加自定义的工具栏按钮。

Parameters

button
Type:
Object|Array

(必须)单个按钮的配置信息或者多个按钮的配置信息。

Returns

Type:
Outline

Outline 对象,便于链式方法调用。

const outline = new Outline(Outline.DEFAULTS)
// 如果需要其它图标,可以到 https://github.com/yaohaixiao/icons.toolkit.vue 项目中选择需要的图标资源
const clean = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 1024 1024">' +
  '<path d="M704 32V320h288a32 32 0 0 1 32 32v320a32 32 0 0 1-32 32H32a32 32 0 0 1-32-32v-320A32 32 0 0 1 32 320H320V32a32 32 0 0 1 32-32h320a32 32 0 0 1 32 32zM576 128H448v320H128v128h768V448H576V128z"></path>' +
  '<path d="M896 576v416a32 32 0 0 1-32 32h-704a32 32 0 0 1-32-32V576h768z m-128 128H256v192h512v-192z"></path>' +
  '</svg>'

outline.addButton({
  name: 'clean',
  // 图标
  icon: clean,
  size: 20,
  color: '#f00'
  // link 指定按钮点击后页面的跳转地址
  link: 'https://github.com/yaohaixiao',
  // link 和 action 只能二选一
  // action 指定按钮的处理方式
  action: {
    type: 'click',
    // 指定回调函数的 this 上下文,不设置 this 指向 toolbar 组件
    context: outline,
    handler: function() {
      // 回调函数的处理逻辑
    }
  }
})

removeButton(name)

Description

removeButton() 方法移除工具栏按钮。

Parameters

name
Type:
String

(必须)按钮名称。

Returns

Type:
Outline

Outline 对象,便于链式方法调用。

const outline = new Outline(Outline.DEFAULTS)
// 如果需要其它图标,可以到 https://github.com/yaohaixiao/icons.toolkit.vue 项目中选择需要的图标资源
const clean = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 1024 1024">' +
  '<path d="M704 32V320h288a32 32 0 0 1 32 32v320a32 32 0 0 1-32 32H32a32 32 0 0 1-32-32v-320A32 32 0 0 1 32 320H320V32a32 32 0 0 1 32-32h320a32 32 0 0 1 32 32zM576 128H448v320H128v128h768V448H576V128z"></path>' +
  '<path d="M896 576v416a32 32 0 0 1-32 32h-704a32 32 0 0 1-32-32V576h768z m-128 128H256v192h512v-192z"></path>' +
  '</svg>'

outline.addButton({
  name: 'clean',
  // 图标
  icon: clean,
  size: 20,
  color: '#f00'
  // link 指定按钮点击后页面的跳转地址
  link: 'https://github.com/yaohaixiao',
  // link 和 action 只能二选一
  // action 指定按钮的处理方式
  action: {
    type: 'click',
    // 指定回调函数的 this 上下文,不设置 this 指向 toolbar 组件
    context: outline,
    handler: function() {
      // 回调函数的处理逻辑
    }
  }
})

setTimeout(() => {
  outline.removeButton('clean')
}, 5000)

toTop([afterScroll])

Description

toTop() 方法会控制页面(scrollElement)滚动到顶部。

Parameters

afterScroll
Type:
Function

(可选)页面停止滚动后的回调函数。

Returns

Type:
Outline

Outline 对象,便于链式方法调用。

const outline = new Outline({
   article: '#article',
   title: 'Outline v2.0.0'
})

outline.toTop() // 页面将滚动到顶部,向上滚动按钮消失
outline.toTop(() => {
  console.log('滚动结束‘)
})

toBottom([afterScroll])

Description

toBottom() 方法会控制页面(scrollElement)滚动到顶部。

Parameters

afterScroll
Type:
Function

(可选)页面停止滚动后的回调函数。

Returns

Type:
Outline

Outline 对象,便于链式方法调用。

const outline = new Outline({
   article: '#article',
   title: 'Outline v2.0.0'
})

outline.toBottom() // 页面将滚动到底部,向下滚动按钮消失
outline.toBottom(() => {
  console.log('滚动结束‘)
})

scrollTo(top[,afterScroll])

Description

scrollTo() 方法用于将窗口的滚动条滚动到指定 top 值的位置。

Parameters

top
Type:
Number

(必选)页面要滚动的 top 数值。

afterScroll
Type:
Function

(可选)页面停止滚动后的回调函数。

Returns

Type:
Outline

Outline 对象,便于链式方法调用。

const outline = new Outline({
     article: '#article',
     title: 'Outline v2.0.0'
})

// -> 页面将滚动到距离顶部 200 像素的位置
outline.scrollTo(200)
outline.scrollTo(200, () => {
  console.log('滚动结束‘)
})

toggle()

Description

toggle() 方法用来隐藏或显示侧边栏菜单。

Returns

Type:
Outline

Outline 对象,便于链式方法调用。

const outline = new Outline({
  article: '#article',
  title: 'Outline v2.0.0'
})

outline.toggle() // 如果已经隐藏,则显示
outline.toggle() // 如果已显示,则隐藏

print()

Description

print() 方法用于启动打印界面,打印当前文章。

Returns

Type:
Outline

Outline 对象,便于链式方法调用。

const outline = new Outline({
     article: '#article',
     title: 'Outline v2.0.0'
})

// 如果浏览器支持 print() 打印,则启动打印界面
outline.print()

destroy()

Description

destroy() 方法用于移除所有绘制的 DOM 节点,并移除绑定的事件处理器,同时重置所有 attrs 配置信息和 data 信息。

Returns

Type:
Outline

Outline 对象,便于链式方法调用。

const outline = new Outline({
   article: '#article',
   title: 'Outline v2.0.0'
})

outline.getChapters()
// -> [{
  code: "1",
  id: 0,
  index: 1,
  level: 1,
  pid: -1
  rel: "heading-0"
  text: "创作灵感"
}]

outline.destroy()
outline.getChapters()
// 调用 destroy() 方法后,所有数据都清空了
// -> []

reload(options)

Description

reload (options) 方法是(根据新的配置信息)重启程序方法:

  1. 先移除所有绘制的 DOM 元素和绑定的事件处理器;
  2. 重新初始化程序;

Parameters

options
Type:
Object

(可选)初始化的配置参数。

Returns

Type:
Outline

Outline 对象,便于链式方法调用。

const outline = new Outline({
  showCode: true
})

// 重启后,将不再显示段落层次编号
outline.reload({
  showCode: false
})

$emit(topic[, data, async = true])

Description

$emit()方法用来发布订阅主题信息。

outline.js 默认是采用异步方式发布的。以确保在消费者处理主题时,主题的发起者不会被阻止。 当然 $emit() 方法也支持同步主题发布。

Category:
Core

Parameters

topic
Type:
String

(必须)主题名称。

data
Type:
Object

(可选)消息传递的数据对象。

async
Type:
Boolean
Default:
true

(可选) 是否异步发布。默认值:true。

  • 当 async 设置为 true(默认) 时,异步发布;
  • 当 async 设置为 false 时,同步发布;

Returns

Type:
Outline

Outline 对象,以便实现链式调用。

const outline = new Outline(Outline.DEFAULTS)

const handler = (msg) => {
  console.log(msg)
}

outline.$on('created', handler)
outline.$on('mounted', handler)

// 异步发布
outline.$emit('mounted') // -> 'ok'

// 同步发布
// 延迟10毫秒:应该看输出 ok 后输出
outline.$emit('created')

$on(topic, handler)

Description

$on() 方法用来订阅主题,并给出处理器函数。

Category:
Core

Parameters

topic
Type:
String

(必须)主题名称。

handler
Type:
Function

((必须)主题的处理器函数。

Returns

Type:
String。

唯一的 token 字符串,例如:'guid-1'。

const outline = new Outline(Outline.DEFAULTS)

const handler = function(attrs) {
  // this 上下文指向 outline 实例
  this.attr()
  console.log('attrs: ', attrs)
}

outline.$on('created', handler)

// 手动触发 created 事件
outline.$emit('created')

$off(topic[, token])

Description

$off() 用来取消订阅主题。

Category:
Core

Parameters

topic
Type:
String

(必须)主题名称。

token
Type:
Function | String

(可选)订阅主题的处理器函数或者唯一 Id 值。

  • 为传递 token 参数:取消指定 topic 的订阅;
  • 传递 token 参数:仅删除 topic 订阅信息中与 token 对应的事件处理器

Returns

Type:
Outline

Outline 对象,以便实现链式调用。

const outline = new Outline(Outline.DEFAULTS)

const handler = (msg) => {
  console.log('handler:', msg)
}

outline.$on('created')

// 取消订阅 author 主题
outline.$off('created')

// 不会有任何反应,因为已经取消订阅了
outline.$emit('created')

Events

outline.js 从 3.21.0 开始提供了 6 事件。通过 outline.js 在 3.21.0 新添加的 $on() 方法监听。

created

事件名称说明回调参数
createdOutline 实例配置信息初始化完成后触发,此时 DOM 元素还没有绘制。返回实例最终的 attrs 配置属性的(对象)值。

Usage

const outline = new Outline()

outline.$on('created', function(attrs) {
  // this 上下文就是 outline 实例
  // attrs === outline.attr()
})

// 当 outline 实例的配置信息初始化完毕,就会触发 created 事件
outline.initialize(Outline.DEFAULTS)

mounted

事件名称说明回调参数
mountedOutline 实例的所有 DOM 元素绘制完毕后触发。--

Usage

const outline = new Outline()

outline.$on('mounted', function() {
  // do something
})

// 当 outline 实例的所有 DOM 绘制完毕,就会触发 mounted 事件
outline.initialize(Outline.DEFAULTS)

enterReading

事件名称说明回调参数
enterReading配置了 print 参数,在进入阅读模式后会触发。--

Usage

const defaults = Outline.DEFAULTS

// 需要配置 print 参数
defaults.print = {
  element: '#article',
  title: document.querySelector('.title')
}

const outline = new Outline(Outline.DEFAULTS)

outline.$on('enterReading', function() {
  // this 上下文就是 outline 实例
  console.log('this', this)
})

// 手动触发 enterReading 事件
outline.$emit('enterReading')

exitReading

事件名称说明回调参数
exitReading配置了 print 参数,在离开阅读模式后会触发。--

Usage

const defaults = Outline.DEFAULTS

// 需要配置 print 参数
defaults.print = {
  element: '#article',
  title: document.querySelector('.title')
}

const outline = new Outline(Outline.DEFAULTS)

outline.$on('exitReading', function() {
  // this 上下文就是 outline 实例
  console.log('this', this)
})

// 手动触发 exitReading 事件
outline.$emit('exitReading')

beforeDestroy

事件名称说明回调参数
beforeDestroyOutline 实例销毁前事件,在调用 Outline 对象的实例 destroy() 方法后会触发。--

Usage

const outline = new Outline(Outline.DEFAULTS)

outline.$on('beforeDestroy', function() {
  // this 上下文就是 outline 实例
  console.log('this', this)
})

outline.destroy()

destroyed

事件名称说明回调参数
destroyedOutline 实例销毁后事件,在调用 Outline 对象的实例 destroy() 方法后会触发。--

Usage

const outline = new Outline(Outline.DEFAULTS)

outline.$on('beforeDestroy', function() {
  // this 上下文就是 outline 实例
  console.log('this', this)
})

outline.destroy()