mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 02:48:55 +08:00
实现简易前端文档检索
This commit is contained in:
parent
fdc4bf546a
commit
f98173fbb9
39
build/generate-search-data.js
Normal file
39
build/generate-search-data.js
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file 生成给前端全文搜索用的文件
|
||||
* @author wuduoyi
|
||||
*/
|
||||
|
||||
const glob = require('glob');
|
||||
const fs = require('fs');
|
||||
let yaml = require('js-yaml');
|
||||
var rYml = /^\s*---([\s\S]*?)---\s/;
|
||||
|
||||
const resultData = {docs: []};
|
||||
|
||||
glob('./docs/**/*.md', {}, function (er, docs) {
|
||||
for (const doc of docs) {
|
||||
let content = fs.readFileSync(doc, {encoding: 'utf8'});
|
||||
let m = rYml.exec(content);
|
||||
let info = {};
|
||||
if (m && m[1]) {
|
||||
info = yaml.safeLoad(m[1]);
|
||||
content = content.substring(m[0].length);
|
||||
}
|
||||
|
||||
const title = info.title || doc;
|
||||
// todo: 属性列表单独处理,检索的时候优先检索
|
||||
resultData.docs.push({
|
||||
title: title,
|
||||
// 去掉注释、换行、图片等
|
||||
body: content
|
||||
.replace(/<\!---.+-->/g, '')
|
||||
.replace(/!?\[.*\]\(.*\)/g, '')
|
||||
.replace(/\n/g, '')
|
||||
.replace(/```.*```/g, '')
|
||||
|
||||
.toLowerCase(),
|
||||
path: doc.replace('.md', '')
|
||||
});
|
||||
}
|
||||
fs.writeFileSync('./public/docs/docs.json', JSON.stringify(resultData));
|
||||
});
|
@ -1,47 +1,79 @@
|
||||
/**
|
||||
* @file 实现前端文档搜索
|
||||
*/
|
||||
import React from 'react';
|
||||
import makeSchemaRenderer from './SchemaRender';
|
||||
|
||||
const FormComponent = makeSchemaRenderer({
|
||||
type: 'form',
|
||||
mode: 'inline',
|
||||
wrapWithPanel: false,
|
||||
className: ':Doc-search',
|
||||
controls: [
|
||||
{
|
||||
type: 'input-group',
|
||||
size: 'sm',
|
||||
controls: [
|
||||
{
|
||||
type: 'icon',
|
||||
addOnclassName: 'no-bg no-border p-r-none p-l',
|
||||
className: 'text-sm',
|
||||
icon: 'search',
|
||||
vendor: 'iconfont'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
placeholder: '搜索...',
|
||||
inputClassName: 'no-border',
|
||||
name: 'docsearch'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
import Axios from 'axios';
|
||||
import SearchBox from '../../src/components/SearchBox';
|
||||
|
||||
export default class DocSearch extends React.Component {
|
||||
docs;
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
searchResults: [],
|
||||
loadError: false
|
||||
};
|
||||
this.onSearch = this.onSearch.bind(this);
|
||||
this.onSearchCancel = this.onSearchCancel.bind(this);
|
||||
}
|
||||
componentDidMount() {
|
||||
// const inputSelector = 'input[name="docsearch"]';
|
||||
// docsearch({
|
||||
// appId: 'S08MJHBHFJ',
|
||||
// apiKey: '5fba814bb773d08b5d2a3f6074f926a5',
|
||||
// indexName: 'gh_pages',
|
||||
// inputSelector,
|
||||
// debug: false
|
||||
// });
|
||||
Axios.get('/docs/docs.json')
|
||||
.then(result => {
|
||||
this.docs = result.data.docs;
|
||||
})
|
||||
.catch(err => {
|
||||
this.setState({loadError: true});
|
||||
});
|
||||
}
|
||||
|
||||
onSearch(query) {
|
||||
if (query === '') {
|
||||
this.setState({searchResults: []});
|
||||
return;
|
||||
}
|
||||
let results = [];
|
||||
for (let doc of this.docs) {
|
||||
let index = doc.body.indexOf(query);
|
||||
|
||||
if (index !== -1) {
|
||||
results.push({
|
||||
title: doc.title,
|
||||
path: doc.path,
|
||||
abstract: doc.body
|
||||
.substring(Math.max(0, index - 20), index + 60)
|
||||
.replace(query, `<strong>${query}</strong>`)
|
||||
});
|
||||
} else if (doc.title.indexOf(query) !== -1) {
|
||||
results.push({
|
||||
title: doc.title,
|
||||
path: doc.path,
|
||||
abstract: ''
|
||||
});
|
||||
}
|
||||
}
|
||||
this.setState({searchResults: results});
|
||||
}
|
||||
|
||||
onSearchCancel() {
|
||||
this.setState({searchResults: []});
|
||||
}
|
||||
|
||||
render() {
|
||||
return <FormComponent showCode={false} theme={this.props.theme} />;
|
||||
const searchResults = this.state.searchResults;
|
||||
return (
|
||||
<div className="p-l p-t">
|
||||
<SearchBox onSearch={this.onSearch} onCancel={this.onSearchCancel} />
|
||||
<div className="search-result">
|
||||
{searchResults.map(item => {
|
||||
return (
|
||||
<a href={'/' + item.path} key={`list_${item.path}`}>
|
||||
<h5>{item.title}</h5>
|
||||
<p dangerouslySetInnerHTML={{__html: item.abstract}} />
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ a {
|
||||
|
||||
.gh-icon {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
right: 15px;
|
||||
top: 15px;
|
||||
font-size: 22px;
|
||||
padding: 0 10px;
|
||||
@ -711,3 +711,13 @@ a {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-result {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.dark {
|
||||
.search-result {
|
||||
background-color: #333538;
|
||||
}
|
||||
}
|
||||
|
@ -126,6 +126,7 @@
|
||||
"fis3-preprocessor-js-require-css": "^0.1.3",
|
||||
"font-awesome": "4.7.0",
|
||||
"fs-walk": "0.0.2",
|
||||
"glob": "^7.1.6",
|
||||
"husky": "^2.2.0",
|
||||
"jest": "^24.5.0",
|
||||
"jest-canvas-mock": "^2.1.0",
|
||||
|
Loading…
Reference in New Issue
Block a user