docs(README): add search
This commit is contained in:
parent
eb5ff3e987
commit
e1da2f8a84
8 changed files with 99 additions and 17 deletions
|
|
@ -1,3 +1,11 @@
|
||||||
|
## 2.1.0
|
||||||
|
### Features
|
||||||
|
- Add search plugin
|
||||||
|
```html
|
||||||
|
<script src="//unpkg.com/docsify/lib/docsify.js"></script>
|
||||||
|
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
## 2.0.3
|
## 2.0.3
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
- fix: rendering emojis
|
- fix: rendering emojis
|
||||||
|
|
|
||||||
|
|
@ -459,3 +459,39 @@ window.$docsify = {
|
||||||
themeColor: '#3F51B5'
|
themeColor: '#3F51B5'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Plugins
|
||||||
|
|
||||||
|
### Full Text Search
|
||||||
|
|
||||||
|
If a document can have a search, can enhance some user experience. The introduction of search plugin is easy. such as
|
||||||
|
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script src="//unpkg.com/docsify/lib/docsify.js"></script>
|
||||||
|
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, the hyperlink on the current page is recognized and the content is saved in `localStorage`. You can also specify the path to the files.
|
||||||
|
|
||||||
|
!> Configure the content before the plugin is installed.
|
||||||
|
|
||||||
|
```js
|
||||||
|
window.$docsify = {
|
||||||
|
search: 'auto', // default
|
||||||
|
|
||||||
|
search : [
|
||||||
|
'/', // => /README.md
|
||||||
|
'/guide', // => /guide.md
|
||||||
|
'/get-started', // => /get-started.md
|
||||||
|
'/zh-cn/', // => /zh-cn/README.md
|
||||||
|
],
|
||||||
|
|
||||||
|
// Full configuration
|
||||||
|
search: {
|
||||||
|
maxAge: 86400000, // Expiration time, the default one day
|
||||||
|
paths: [], // or 'auto'
|
||||||
|
placeholder: 'Type to search'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -466,3 +466,38 @@ window.$docsify = {
|
||||||
themeColor: '#3F51B5'
|
themeColor: '#3F51B5'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Plugins
|
||||||
|
|
||||||
|
### 全文检索 - search
|
||||||
|
|
||||||
|
一份文档如果能有搜索功能会提升一些用户体验,加载搜索插件也很简单,直接引入就自动安装并启用。默认情况下会自动分析当前页面上的超链接,获取内容后建立索引并存储在 localStorage 里,默认过期时间为一天,当然这是可配置的。
|
||||||
|
|
||||||
|
自动识别的方式不一定能识别完整或者如果你想指定某些文件可索引,你可以自己指定文件的路径。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script src="//unpkg.com/docsify/lib/docsify.js"></script>
|
||||||
|
<script src="//unpkg.com/docsify/lib/plugins/search.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
!> 配置要在 docsify 引入之前
|
||||||
|
|
||||||
|
```js
|
||||||
|
window.$docsify = {
|
||||||
|
search: 'auto', // default
|
||||||
|
|
||||||
|
search : [
|
||||||
|
'/', // => /README.md
|
||||||
|
'/guide', // => /guide.md
|
||||||
|
'/get-started', // => /get-started.md
|
||||||
|
'/zh-cn/', // => /zh-cn/README.md
|
||||||
|
],
|
||||||
|
|
||||||
|
// Full configuration
|
||||||
|
search: {
|
||||||
|
maxAge: 86400000, // Expiration time, the default one day
|
||||||
|
paths: [], // or 'auto'
|
||||||
|
placeholder: 'Type to search'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ export function bindToggle (dom) {
|
||||||
dom.addEventListener('click', () => body.classList.toggle('close'))
|
dom.addEventListener('click', () => body.classList.toggle('close'))
|
||||||
|
|
||||||
if (isMobile()) {
|
if (isMobile()) {
|
||||||
const sidebar = document.querySelector('.sidebar div')
|
const sidebar = document.querySelector('.sidebar')
|
||||||
sidebar.addEventListener('click', () => {
|
sidebar.addEventListener('click', () => {
|
||||||
body.classList.toggle('close')
|
body.classList.toggle('close')
|
||||||
setTimeout(() => activeLink(sidebar, true), 0)
|
setTimeout(() => activeLink(sidebar, true), 0)
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ const mainRender = function (cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let page
|
let page
|
||||||
|
|
||||||
if (!route) {
|
if (!route) {
|
||||||
page = OPTIONS.homepage || 'README.md'
|
page = OPTIONS.homepage || 'README.md'
|
||||||
} else if (/\/$/.test(route)) {
|
} else if (/\/$/.test(route)) {
|
||||||
|
|
|
||||||
|
|
@ -50,14 +50,14 @@ const genFilePath = function (path) {
|
||||||
|
|
||||||
filePath = basePath + filePath
|
filePath = basePath + filePath
|
||||||
|
|
||||||
return filePath.replace(/\/\//g, '/')
|
return filePath.replace(/\/+/g, '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generate index
|
* generate index
|
||||||
*/
|
*/
|
||||||
const genIndex = function (path, content = '') {
|
const genIndex = function (path, content = '') {
|
||||||
// INDEXS[path] = {}
|
INDEXS[path] = { slug: '', title: '', body: '' }
|
||||||
let slug
|
let slug
|
||||||
|
|
||||||
content
|
content
|
||||||
|
|
@ -73,7 +73,7 @@ const genIndex = function (path, content = '') {
|
||||||
// <h1 id="xxx"></h1>
|
// <h1 id="xxx"></h1>
|
||||||
const id = attr.match(/id="(\S+)"/)[1]
|
const id = attr.match(/id="(\S+)"/)[1]
|
||||||
|
|
||||||
slug = `#/${path}#${id}`.replace(/\/\//, '/')
|
slug = `#/${path}#${id}`.replace(/\/+/, '/')
|
||||||
INDEXS[slug] = { slug, title: text, body: '' }
|
INDEXS[slug] = { slug, title: text, body: '' }
|
||||||
} else {
|
} else {
|
||||||
// other html tag
|
// other html tag
|
||||||
|
|
@ -221,12 +221,10 @@ class SearchComponent {
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
const post = data[i]
|
const post = data[i]
|
||||||
let isMatch = false
|
let isMatch = false
|
||||||
let matchingNum = 0
|
|
||||||
let resultStr = ''
|
let resultStr = ''
|
||||||
const postTitle = post.title && post.title.trim()
|
const postTitle = post.title && post.title.trim()
|
||||||
const postContent = post.body && post.body.trim()
|
const postContent = post.body && post.body.trim()
|
||||||
const postUrl = post.slug || ''
|
const postUrl = post.slug || ''
|
||||||
const postType = post.pagetitle
|
|
||||||
|
|
||||||
if (postTitle !== '' && postContent !== '') {
|
if (postTitle !== '' && postContent !== '') {
|
||||||
keywords.forEach((keyword, i) => {
|
keywords.forEach((keyword, i) => {
|
||||||
|
|
@ -241,7 +239,6 @@ class SearchComponent {
|
||||||
isMatch = false
|
isMatch = false
|
||||||
} else {
|
} else {
|
||||||
isMatch = true
|
isMatch = true
|
||||||
matchingNum++
|
|
||||||
if (indexContent < 0) indexContent = 0
|
if (indexContent < 0) indexContent = 0
|
||||||
|
|
||||||
let start = 0
|
let start = 0
|
||||||
|
|
@ -266,9 +263,7 @@ class SearchComponent {
|
||||||
const matchingPost = {
|
const matchingPost = {
|
||||||
title: escapeHtml(postTitle),
|
title: escapeHtml(postTitle),
|
||||||
content: resultStr,
|
content: resultStr,
|
||||||
url: postUrl,
|
url: postUrl
|
||||||
type: postType,
|
|
||||||
matchingNum: matchingNum
|
|
||||||
}
|
}
|
||||||
|
|
||||||
matchingResults.push(matchingPost)
|
matchingResults.push(matchingPost)
|
||||||
|
|
@ -280,23 +275,30 @@ class SearchComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 如果不存在就重新加载
|
|
||||||
const searchPlugin = function () {
|
const searchPlugin = function () {
|
||||||
if (localStorage.getItem('docsify.search.expires') > Date.now()) {
|
const isAuto = CONFIG.paths === 'auto'
|
||||||
INDEXS = JSON.parse(localStorage.getItem('docsify.search.index'))
|
const isExpired = localStorage.getItem('docsify.search.expires') < Date.now()
|
||||||
|
|
||||||
|
INDEXS = JSON.parse(localStorage.getItem('docsify.search.index'))
|
||||||
|
|
||||||
|
if (isExpired) {
|
||||||
|
INDEXS = {}
|
||||||
|
} else if (!isAuto) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const paths = CONFIG.paths === 'auto' ? getAllPaths() : CONFIG.paths
|
let count = 0
|
||||||
|
const paths = isAuto ? getAllPaths() : CONFIG.paths
|
||||||
const len = paths.length
|
const len = paths.length
|
||||||
const { load, marked, slugify } = window.Docsify.utils
|
const { load, marked, slugify } = window.Docsify.utils
|
||||||
let count = 0
|
|
||||||
const done = () => {
|
const done = () => {
|
||||||
localStorage.setItem('docsify.search.expires', Date.now() + CONFIG.maxAge)
|
localStorage.setItem('docsify.search.expires', Date.now() + CONFIG.maxAge)
|
||||||
localStorage.setItem('docsify.search.index', JSON.stringify(INDEXS))
|
localStorage.setItem('docsify.search.index', JSON.stringify(INDEXS))
|
||||||
}
|
}
|
||||||
|
|
||||||
paths.forEach(path => {
|
paths.forEach(path => {
|
||||||
|
if (INDEXS[path]) return count++
|
||||||
|
|
||||||
load(genFilePath(path)).then(content => {
|
load(genFilePath(path)).then(content => {
|
||||||
genIndex(path, marked(content))
|
genIndex(path, marked(content))
|
||||||
slugify.clear()
|
slugify.clear()
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ export function init () {
|
||||||
}
|
}
|
||||||
renderer.link = function (href, title, text) {
|
renderer.link = function (href, title, text) {
|
||||||
if (!/:/.test(href)) {
|
if (!/:/.test(href)) {
|
||||||
href = `#/${href}`.replace(/\/\//g, '/')
|
href = `#/${href}`.replace(/\/+/g, '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
return `<a href="${href}" title="${title || ''}">${text}</a>`
|
return `<a href="${href}" title="${title || ''}">${text}</a>`
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ export function getRoute () {
|
||||||
const loc = window.location
|
const loc = window.location
|
||||||
if (cacheHash === loc.hash && !isNil(cacheRoute)) return cacheRoute
|
if (cacheHash === loc.hash && !isNil(cacheRoute)) return cacheRoute
|
||||||
|
|
||||||
let route = loc.hash.match(/^#\/([^#]+)/)
|
let route = loc.hash.replace(/%23/g, '#').match(/^#\/([^#]+)/)
|
||||||
|
|
||||||
if (route && route.length === 2) {
|
if (route && route.length === 2) {
|
||||||
route = route[1]
|
route = route[1]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue