提交 c963481c 编写于 作者: D DCloud_LXH

Merge branch 'vuepress-searchpage' into vuepress-dev

......@@ -36,7 +36,7 @@ const config = {
apiKey: '2fdcc4e76c8e260671ad70065e60b2e7',
indexName: 'zh-uniapp',
appId: 'PQIR5NL8CZ',
searchParameters: { hitsPerPage: 80 }
searchParameters: { hitsPerPage: 50 }
}
},
markdown: {
......@@ -64,6 +64,29 @@ const config = {
.plugin('normallize-link')
.use(require('./markdown/normallizeLink'))
}
},
chainWebpack: (config, isServer) => {
console.log('config :>> ', config);
config.devServer.proxy({
'/ext': {
target: 'http://localhost:3000', // 后台api
changeOrigin: true, //是否跨域
secure: false,
// secure: true,
pathRewrite: {
'^/ext': '' //需要rewrite的,
}
},
'/ask': {
target: 'https://ask.dcloud.net.cn', // 后台api
changeOrigin: true, //是否跨域
secure: false,
// secure: true,
pathRewrite: {
'^/ask': '' //需要rewrite的,
}
}
})
}
}
......
<template>
<div id="docsearch"></div>
<div id="docsearch">
<button type="button" class="DocSearch DocSearch-Button" aria-label="搜索文档" @click="openSearch">
<span class="DocSearch-Button-Container">
<svg width="20" height="20" class="DocSearch-Search-Icon" viewBox="0 0 20 20">
<path
d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z"
stroke="currentColor"
fill="none"
fill-rule="evenodd"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
<span class="DocSearch-Button-Placeholder">搜索文档</span>
</span>
<span class="DocSearch-Button-Keys">
<span class="DocSearch-Button-Key">
<svg width="15" height="15" class="DocSearch-Control-Key-Icon">
<path
d="M4.505 4.496h2M5.505 5.496v5M8.216 4.496l.055 5.993M10 7.5c.333.333.5.667.5 1v2M12.326 4.5v5.996M8.384 4.496c1.674 0 2.116 0 2.116 1.5s-.442 1.5-2.116 1.5M3.205 9.303c-.09.448-.277 1.21-1.241 1.203C1 10.5.5 9.513.5 8V7c0-1.57.5-2.5 1.464-2.494.964.006 1.134.598 1.24 1.342M12.553 10.5h1.953"
stroke-width="1.2"
stroke="currentColor"
fill="none"
stroke-linecap="square"
></path>
</svg>
</span>
<span class="DocSearch-Button-Key">K</span>
</span>
</button>
</div>
</template>
<script>
import '@docsearch/css';
import { createElement } from 'preact';
const resolveRoutePathFromUrl = (url, base = '/') =>
url
// remove url origin
.replace(/^(https?:)?\/\/[^/]*/, '')
// remove site base
.replace(new RegExp(`^${base}`), '/');
const loadDocsearch = async () => {
const docsearch = await import('@docsearch/js');
return docsearch.default;
};
const isSpecialClick = event => {
return event.button === 1 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
};
const translations = {
button: {
buttonText: '搜索文档',
buttonAriaLabel: '搜索文档',
},
modal: {
searchBox: {
resetButtonTitle: '清除查询条件',
resetButtonAriaLabel: '清除查询条件',
cancelButtonText: '取消',
cancelButtonAriaLabel: '取消',
},
startScreen: {
recentSearchesTitle: '搜索历史',
noRecentSearchesText: '搜索历史为空',
saveRecentSearchButtonTitle: '收藏',
removeRecentSearchButtonTitle: '从搜索记录中移除',
favoriteSearchesTitle: '收藏',
removeFavoriteSearchButtonTitle: '从收藏中移除',
},
errorScreen: {
titleText: '无法获取结果',
helpText: '请检查一下网络连接',
},
footer: {
selectText: '选择',
navigateText: '切换',
closeText: '关闭',
searchByText: '搜索提供者',
},
noResultsScreen: {
noResultsText: '无法找到相关结果',
suggestedQueryText: '你可以尝试查询',
reportMissingResultsText: '你认为查询该有结果?',
reportMissingResultsLinkText: '点击反馈',
},
},
};
export default {
name: 'AlgoliaSearchBox',
props: ['options'],
watch: {},
watch: {
$lang(newValue) {
this.update(this.options, newValue);
},
options(newValue) {
this.update(newValue, this.$lang);
},
},
mounted() {
this.initialize(this.options, this.$lang);
},
mounted() {},
methods: {
initialize(userOptions, lang) {
loadDocsearch().then(docsearch => {
const { searchParameters = {} } = userOptions;
docsearch(
Object.assign({}, userOptions, {
placeholder: '搜索',
translations,
container: '#docsearch',
// #697 Make docsearch work well at i18n mode.
searchParameters: {
...searchParameters,
facetFilters: [`lang:${lang}`].concat(searchParameters.facetFilters || []),
},
navigator: {
// when pressing Enter without metaKey
navigate: ({ itemUrl }) => {
this.$router.push(itemUrl);
},
},
/* getMissingResultsUrl: ({ query }) =>
`https://github.com/dcloudio/uni-app/issues/new?title=${query}`, */
// transform full url to route path
transformItems: items =>
items.map(item => {
// the `item.url` is full url with protocol and hostname
// so we have to transform it to vue-router path
return {
...item,
url: resolveRoutePathFromUrl(item.url, this.$site.base),
};
}),
// handle `onClick` by `this.$routerpush`
hitComponent: ({ hit, children }) =>
createElement(
'a',
{
href: hit.url,
onClick: event => {
if (isSpecialClick(event)) {
return;
}
event.preventDefault();
this.$router.push(hit.url);
},
},
children
),
})
);
});
},
update(options, lang) {
this.$el.innerHTML = '<div id="docsearch"></div>';
this.initialize(options, lang);
},
openSearch(){
this.$parent.$refs.dcloudSearchPage.onSearchOpen()
}
},
};
</script>
......
<template>
<li :class="li_class">
<a :href="item.url" @click="onSearchClose">
<div class="DocSearch-Hit-Container">
<div
class="DocSearch-Hit-content-wrapper"
v-if="item.hierarchy[item.type] && item.type === 'lvl1'"
>
<span class="DocSearch-Hit-title" v-html="snippetResultContent('hierarchy.lvl1')" />
<span
v-if="item.content"
class="DocSearch-Hit-path"
v-html="snippetResultContent('content')"
/>
</div>
<div v-else-if="isContent" class="DocSearch-Hit-content-wrapper">
<span class="DocSearch-Hit-title" v-html="snippetResultContent('content')" />
<span class="DocSearch-Hit-path" v-html="snippetResultContent('hierarchy.lvl1')" />
</div>
<div v-else class="DocSearch-Hit-content-wrapper">
<span
class="DocSearch-Hit-title"
v-html="snippetResultContent(`hierarchy.${item.type}`)"
/>
<span class="DocSearch-Hit-path" v-html="snippetResultContent('hierarchy.lvl1')" />
</div>
</div>
</a>
</li>
</template>
<script>
function getPropertyByPath(object, path) {
const parts = path.split('.');
return parts.reduce((prev, current) => {
if (prev?.[current]) return prev[current];
return null;
}, object);
}
export default {
data() {
return {};
},
inject: ['onSearchClose'],
props: {
item: {
type: Object,
default: () => ({}),
},
index: {
type: Number,
default: 0,
},
},
computed: {
li_class() {
return ['DocSearch-Hit', this.item.__docsearch_parent && 'DocSearch-Hit--Child']
.filter(Boolean)
.join(' ');
},
isContent() {
return this.item.type === 'content';
},
},
methods: {
snippetResultContent(attribute) {
return (
getPropertyByPath(this.item, `_snippetResult.${attribute}.value`) ||
getPropertyByPath(this.item, attribute)
);
},
},
};
</script>
<style lang="stylus">
.DocSearch-Hit
border-radius 0px
display flex
padding-bottom 0px
position relative
&:not(:first-child)
border-top 1px solid #f5f6f7
a
background var(--docsearch-hit-background)
border-radius 0px
// box-shadow var(--docsearch-hit-shadow)
box-shadow none
display block
padding-left var(--docsearch-spacing)
width 100%
.DocSearch-Hit-Container
align-items center
color #444950
display flex
flex-direction row
height 56px
padding 0 12px 0 0
.DocSearch-Hit-content-wrapper
overflow hidden
display flex
flex 1 1 auto
flex-direction column
font-weight 500
justify-content center
line-height 1.2em
margin 0 8px
overflow-x hidden
position relative
text-overflow ellipsis
white-space nowrap
width 80%
.DocSearch-Hit-title
font-size 0.9em
.DocSearch-Hit-path
// color $accentColor
font-size 0.75em
</style>
<template>
<section class="DocSearch-Hits">
<div class="DocSearch-Hit-source">{{ title }}</div>
<ul id="docsearch-list">
<template v-for="(item, index) in results">
<Result :key="[title, item.objectID].join(':')" :item="item" :index="index" />
</template>
</ul>
</section>
</template>
<script>
import Result from './Result.vue';
export default {
components: { Result },
data() {
return {};
},
props: {
title: {
type: String,
default: '文档',
},
results: {
type: Array,
default: [],
},
},
methods: {},
};
</script>
<style lang="stylus">
#docsearch-list{
border-radius: 10px;
padding: 0;
}
.DocSearch-Hits mark {
background: none;
color: $accentColor;
}
.DocSearch-Hit-source {
background-color $search-container-color;
color: $accentColor;
}
</style>
<template>
<!-- 分页结构 -->
<div class="page-bar">
<ul>
<li v-if="cur > 1"><a class="clearfix" v-on:click="cur--, pageClick()">上一页</a></li>
<li v-if="cur == 1"><a class="banclick clearfix">上一页</a></li>
<template v-for="index in indexs">
<li :key="index" :class="{ active: cur == index }">
<a class="clearfix" v-on:click="btnClick(index)">{{ index }}</a>
</li>
</template>
<li v-if="cur != all"><a class="clearfix" v-on:click="cur++, pageClick()">下一页</a></li>
<li v-if="cur == all"><a class="banclick clearfix">下一页</a></li>
<li>
<span>
<i>{{ all }}</i>
</span>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
all: 10, //总页数
cur: 1, //当前页码
// totalPage: 0, //当前条数
};
},
props: {
curPage: {
type: Number,
default: 1,
},
totalPage: {
type: Number,
default: 0,
},
},
created() {
this.all = this.totalPage;
this.cur = this.curPage;
},
watch: {
curPage: {
immediate: true,
handler(val) {
this.cur = val;
},
},
totalPage: {
immediate: true,
handler(val) {
this.all = val;
},
},
},
methods: {
//请求数据
dataListFn: function (index) {
this.$emit('research', index);
},
//分页
btnClick: function (data) {
if (data != this.cur) {
this.cur = data;
this.dataListFn(this.cur);
}
},
pageClick: function () {
this.dataListFn(this.cur);
},
},
computed: {
//分页
indexs: function () {
var left = 1;
var right = this.all;
var ar = [];
if (this.all >= 5) {
if (this.cur > 3 && this.cur < this.all - 2) {
left = this.cur - 2;
right = this.cur + 2;
} else {
if (this.cur <= 3) {
left = 1;
right = 5;
} else {
right = this.all;
left = this.all - 4;
}
}
}
while (left <= right) {
ar.push(left);
left++;
}
return ar;
},
},
};
</script>
<style lang="stylus" scoped>
.page-bar
display flex
justify-content center
margin 10px
ul, li
margin 0px
padding 0px
user-select none
li
display inline-block
list-style none
overflow hidden
.page-bar li:first-child > a
margin-left 0px
.page-bar a
border 1px solid #ddd
text-decoration none
position relative
float left
padding 2px 10px
margin-left -1px
line-height 1.42857143
color #5d6062
cursor pointer
margin-right 20px
background-color #fff
.page-bar a:hover
background-color #eee
.page-bar a.banclick
cursor not-allowed
.page-bar .active a
color #fff
cursor default
background-color $accentColor
border-color $accentColor
.page-bar i
font-style normal
color $accentColor
margin 0px 4px
font-size 12px
</style>
$svg-color = #b1b2b3
$svg-hover-color = #9b9b9b
#search-container
position relative
overflow auto
position fixed
width 100vw
height 100vh
left 0
top 0
z-index 200
background-color $search-container-color
.sub-navbar, .result-wrap
width 80%
max-width 960px
margin 0 auto
.search-wrap
width 100%
display inline-block
vertical-align middle
position relative
.input-wrap
margin-top 24px
position relative
display flex
align-items center
box-sizing border-box
.search-input-btn
display flex
flex-direction column
justify-content center
padding 0
font-size 0
background-color #fff
button
width 40px
font-family inherit
font-size 100%
margin 0
outline 0
background-color transparent
padding 0
border-width 0
vertical-align middle
cursor pointer
svg
fill $svg-color
&:hover
fill $svg-hover-color
.search-input
width 100%
height 56px
font-size 16px
border none
box-sizing border-box
outline none
padding 1px 10px
border-radius 4px
.search-input-btn
height 56px
.search-back__btn
display block !important
font-size 17px
color #576b95
line-height 24px
padding 10px 16px
white-space nowrap
/* position absolute
right -65px */
.search-category
.navbar
border none
.main-navbar
box-shadow none
.main-navbar-links
width 100%
padding 0
@media (max-width 630px)
&
white-space normal !important
.main-navbar-item
@media (max-width 1070px)
&
padding 0 2%
@media (max-width 900px)
&
padding 0 1%
.result-number
display flex
justify-content center
align-items center
margin-top 20px
font-size 20px
.DocSearch-Logo
font-size 16px
vertical-align middle
display inline-block
.search-result
box-sizing border-box
.result-wrap
ul
list-style none
margin 0
padding 0
@media (max-width $MQMobile)
#search-container
.search-navbar-header>.main-navbar
display none !important
.search-navbar>.navbar, .search-category>.navbar
line-height 3rem
height auto
position static !important
.sub-navbar, .result-wrap
width 100% !important
.input-wrap
padding-left 5px
margin-top 5px !important
.search-input, .search-input-btn
height 32px !important
.search-result
padding 0 10px
.search-result-aside
display none
#search-container
.search-result-aside
height 100px
position absolute
top 80px
right 100px
.search-result-aside-link
display flex
flex-direction column
justify-content center
align-items flex-start
.markdown-section
margin-top 20px
background-color #fff
padding 10px
.matching-post
$padding-n = 25px
padding $padding-n $padding-n 10px $padding-n
&:not(:last-child)
border-bottom 1px solid #eee
&:first-child
margin-top 0 !important
a
text-decoration none
color inherit
font-weight 400
&:hover
color $accentColor
.post-wrapper
display flex
p.aw-text
margin 0
display inline-flex
p
font-size 14px
overflow hidden
text-overflow ellipsis
display -webkit-box
-webkit-line-clamp 2
-webkit-box-orient vertical
.post-tag
background-color #f0f0f0
font-size 13px
padding 2px 4px
color #999
border-radius 3px
margin-right 5px
.matching-post h2
margin-top 0
padding-top 0
h2
color #2c3e50
font-size 17px
margin 0
padding 0
display inline-block
font-weight 600
border none
.search-keyword
font-style normal
font-weight 700
color $accentColor
\ No newline at end of file
<template>
<div v-if="openSearch" id="search-container" ref="pageContainer">
<div class="search-navbar">
<div class="search-navbar-header navbar">
<div class="main-navbar">
<NavbarLogo />
<div class="main-navbar-links can-hide">
<div class="main-navbar-item active"></div>
</div>
</div>
<div class="sub-navbar">
<div class="search-wrap">
<div class="input-wrap">
<input
ref="searchInput"
class="search-input"
:placeholder="placeholder"
type="text"
@keydown.enter="resetSearchPage, search"
v-model="searchValue"
/>
<span class="search-input-btn">
<button @click="resetSearchPage, search">
<svg
width="16"
height="16"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.33 10.007l4.273 4.273a.502.502 0 0 1 .005.709l-.585.584a.499.499 0 0 1-.709-.004L10.046 11.3a6.278 6.278 0 1 1 1.284-1.294zm.012-3.729a5.063 5.063 0 1 0-10.127 0 5.063 5.063 0 0 0 10.127 0z"
></path>
</svg>
</button>
</span>
<a href="javascript:;" class="search-back__btn" @click="onSearchClose">取消</a>
</div>
<div class="search-category">
<div class="navbar">
<div class="main-navbar">
<div class="main-navbar-links">
<template v-for="(item, index) in category">
<div :class="mainNavLinkClass(index)" :key="item.text">
<MainNavbarLink
:key="item.text"
v-if="item.link"
:item="{
...item,
link: searchLink(item.link),
}"
/>
<a v-else href="javascript:;" @click="switchCategory(index)">
{{ item.text }}
</a>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="result-number">
<span>共{{ curHits }}个相关结果</span>
</div>
<div class="search-result">
<div class="result-wrap">
<template v-if="isAlgolia && resultList.length">
<template v-for="item in resultList">
<Results :key="item.id" :title="item.title" :results="item.items" />
</template>
</template>
<template v-else>
<div
class="markdown-section search-result-list"
v-if="serverHtml"
v-html="serverHtml"
></div>
</template>
</div>
<div v-if="isAlgolia" style="display: flex; justify-content: center; margin: 10px 0 20px">
<div class="DocSearch-Logo">
<a
href="https://www.algolia.com/ref/docsearch/?utm_source=uniapp.dcloud.io&amp;utm_medium=referral&amp;utm_content=powered_by&amp;utm_campaign=docsearch"
target="_blank"
rel="noopener noreferrer"
>
<span class="DocSearch-Label">搜索提供者</span>
<svg width="77" height="19" aria-label="Algolia" role="img">
<path
d="M2.5067 0h14.0245c1.384.001 2.5058 1.1205 2.5068 2.5017V16.5c-.0014 1.3808-1.1232 2.4995-2.5068 2.5H2.5067C1.1232 18.9995.0014 17.8808 0 16.5V2.4958A2.495 2.495 0 01.735.7294 2.505 2.505 0 012.5068 0zM37.95 15.0695c-3.7068.0168-3.7068-2.986-3.7068-3.4634L34.2372.3576 36.498 0v11.1794c0 .2715 0 1.9889 1.452 1.994v1.8961zm-9.1666-1.8388c.694 0 1.2086-.0397 1.5678-.1088v-2.2934a5.3639 5.3639 0 00-1.3303-.1679 4.8283 4.8283 0 00-.758.0582 2.2845 2.2845 0 00-.688.2024c-.2029.0979-.371.2362-.4919.4142-.1268.1788-.185.2826-.185.5533 0 .5297.185.8359.5205 1.0375.3355.2016.7928.3053 1.365.3053v-.0008zm-.1969-8.1817c.7463 0 1.3768.092 1.8856.2767.5088.1838.9195.4428 1.2204.7717.3068.334.5147.7777.6423 1.251.1327.4723.196.991.196 1.5603v5.798c-.5235.1036-1.05.192-1.5787.2649-.7048.1037-1.4976.156-2.3774.156-.5832 0-1.1215-.0582-1.6016-.167a3.385 3.385 0 01-1.2432-.5364 2.6034 2.6034 0 01-.8037-.9565c-.191-.3922-.29-.9447-.29-1.5208 0-.5533.11-.905.3246-1.2863a2.7351 2.7351 0 01.8849-.9329c.376-.242.8029-.415 1.2948-.5187a7.4517 7.4517 0 011.5381-.156 7.1162 7.1162 0 011.6667.2024V8.886c0-.259-.0296-.5061-.093-.7372a1.5847 1.5847 0 00-.3245-.6158 1.5079 1.5079 0 00-.6119-.4158 2.6788 2.6788 0 00-.966-.173c-.5206 0-.9948.0634-1.4283.1384a6.5481 6.5481 0 00-1.065.259l-.2712-1.849c.2831-.0986.7048-.1964 1.2491-.2943a9.2979 9.2979 0 011.752-.1501v.0008zm44.6597 8.1193c.6947 0 1.2086-.0405 1.567-.1097v-2.2942a5.3743 5.3743 0 00-1.3303-.1679c-.2485 0-.503.0177-.7573.0582a2.2853 2.2853 0 00-.688.2024 1.2333 1.2333 0 00-.4918.4142c-.1268.1788-.1843.2826-.1843.5533 0 .5297.1843.8359.5198 1.0375.3414.2066.7927.3053 1.365.3053v.0009zm-.191-8.1767c.7463 0 1.3768.0912 1.8856.2759.5087.1847.9195.4436 1.2204.7717.3.329.5147.7786.6414 1.251a5.7248 5.7248 0 01.197 1.562v5.7972c-.3466.0742-.874.1602-1.5788.2648-.7049.1038-1.4976.1552-2.3774.1552-.5832 0-1.1215-.0573-1.6016-.167a3.385 3.385 0 01-1.2432-.5356 2.6034 2.6034 0 01-.8038-.9565c-.191-.3922-.2898-.9447-.2898-1.5216 0-.5533.1098-.905.3245-1.2854a2.7373 2.7373 0 01.8849-.9338c.376-.2412.8029-.4141 1.2947-.5178a7.4545 7.4545 0 012.325-.1097c.2781.0287.5672.081.879.156v-.3686a2.7781 2.7781 0 00-.092-.738 1.5788 1.5788 0 00-.3246-.6166 1.5079 1.5079 0 00-.612-.415 2.6797 2.6797 0 00-.966-.1729c-.5205 0-.9947.0633-1.4282.1384a6.5608 6.5608 0 00-1.065.259l-.2712-1.8498c.283-.0979.7048-.1957 1.2491-.2935a9.8597 9.8597 0 011.752-.1494zm-6.79-1.072c-.7576.001-1.373-.6103-1.3759-1.3664 0-.755.6128-1.3664 1.376-1.3664.764 0 1.3775.6115 1.3775 1.3664s-.6195 1.3664-1.3776 1.3664zm1.1393 11.1507h-2.2726V5.3409l2.2734-.3568v10.0845l-.0008.0017zm-3.984 0c-3.707.0168-3.707-2.986-3.707-3.4642L59.7069.3576 61.9685 0v11.1794c0 .2715 0 1.9889 1.452 1.994V15.0703zm-7.3512-4.979c0-.975-.2138-1.7873-.6305-2.3516-.4167-.571-.9998-.852-1.747-.852-.7454 0-1.3302.281-1.7452.852-.4166.5702-.6195 1.3765-.6195 2.3516 0 .9851.208 1.6473.6254 2.2183.4158.576.9998.8587 1.7461.8587.7454 0 1.3303-.2885 1.747-.8595.4158-.5761.6237-1.2315.6237-2.2184v.0009zm2.3132-.006c0 .7609-.1099 1.3361-.3356 1.9654a4.654 4.654 0 01-.9533 1.6076A4.214 4.214 0 0155.613 14.69c-.579.2412-1.4697.3795-1.9143.3795-.4462-.005-1.3303-.1324-1.9033-.3795a4.307 4.307 0 01-1.474-1.0316c-.4115-.4445-.7293-.9801-.9609-1.6076a5.3423 5.3423 0 01-.3465-1.9653c0-.7608.104-1.493.3356-2.1155a4.683 4.683 0 01.9719-1.5958 4.3383 4.3383 0 011.479-1.0257c.5739-.242 1.2043-.3567 1.8864-.3567.6829 0 1.3125.1197 1.8906.3567a4.1245 4.1245 0 011.4816 1.0257 4.7587 4.7587 0 01.9592 1.5958c.2426.6225.3643 1.3547.3643 2.1155zm-17.0198 0c0 .9448.208 1.9932.6238 2.431.4166.4386.955.6579 1.6142.6579.3584 0 .6998-.0523 1.0176-.1502.3186-.0978.5721-.2134.775-.3517V7.0784a8.8706 8.8706 0 00-1.4926-.1906c-.8206-.0236-1.4452.312-1.8847.8468-.4335.5365-.6533 1.476-.6533 2.3516v-.0008zm6.2863 4.4485c0 1.5385-.3938 2.662-1.1866 3.3773-.791.7136-2.0005 1.0712-3.6308 1.0712-.5958 0-1.834-.1156-2.8228-.334l.3643-1.7865c.8282.173 1.9202.2193 2.4932.2193.9077 0 1.555-.1847 1.943-.5533.388-.3686.578-.916.578-1.643v-.3687a6.8289 6.8289 0 01-.8848.3349c-.3634.1096-.786.167-1.261.167-.6246 0-1.1917-.0979-1.7055-.2944a3.5554 3.5554 0 01-1.3244-.8645c-.3642-.3796-.6541-.8579-.8561-1.4289-.2028-.571-.3068-1.59-.3068-2.339 0-.7034.1099-1.5856.3245-2.1735.2198-.5871.5316-1.0949.9542-1.515.4167-.42.9255-.743 1.5213-.98a5.5923 5.5923 0 012.052-.3855c.7353 0 1.4114.092 2.0707.2024.6592.1088 1.2204.2236 1.6776.35v8.945-.0008zM11.5026 4.2418v-.6511c-.0005-.4553-.3704-.8241-.8266-.8241H8.749c-.4561 0-.826.3688-.8265.824v.669c0 .0742.0693.1264.1445.1096a6.0346 6.0346 0 011.6768-.2362 6.125 6.125 0 011.6202.2185.1116.1116 0 00.1386-.1097zm-5.2806.852l-.3296-.3282a.8266.8266 0 00-1.168 0l-.393.3922a.8199.8199 0 000 1.164l.3237.323c.0524.0515.1268.0397.1733-.0117.191-.259.3989-.507.6305-.7372.2374-.2362.48-.4437.7462-.6335.0575-.0354.0634-.1155.017-.1687zm3.5159 2.069v2.818c0 .081.0879.1392.1622.0987l2.5102-1.2964c.0574-.0287.0752-.0987.0464-.1552a3.1237 3.1237 0 00-2.603-1.574c-.0575 0-.115.0456-.115.1097l-.0008-.0009zm.0008 6.789c-2.0933.0005-3.7915-1.6912-3.7947-3.7804C5.9468 8.0821 7.6452 6.39 9.7387 6.391c2.0932-.0005 3.7911 1.6914 3.794 3.7804a3.7783 3.7783 0 01-1.1124 2.675 3.7936 3.7936 0 01-2.6824 1.1054h.0008zM9.738 4.8002c-1.9218 0-3.6975 1.0232-4.6584 2.6841a5.359 5.359 0 000 5.3683c.9609 1.661 2.7366 2.6841 4.6584 2.6841a5.3891 5.3891 0 003.8073-1.5725 5.3675 5.3675 0 001.578-3.7987 5.3574 5.3574 0 00-1.5771-3.797A5.379 5.379 0 009.7387 4.801l-.0008-.0008z"
fill="currentColor"
fill-rule="evenodd"
></path>
</svg>
</a>
</div>
</div>
<div class="search-pagination">
<pagination
v-show="showPagination"
@research="research"
:totalPage="totalPage"
:curPage="curPage"
:pageSize="pageSize"
/>
</div>
</div>
</div>
</template>
<script>
import NavbarLogo from '../NavbarLogo.vue';
import Results from './components/Results.vue';
import pagination from './components/pagination.vue';
import MainNavbarLink from '../MainNavbarLink.vue';
import { search as searchClient } from './searchClient';
import { postExt, postAsk } from './postDcloudServer';
import {
forbidScroll,
removeHighlightTags,
debounce,
isEditingContent,
Base64Encode,
} from '../../util';
const resolveRoutePathFromUrl = (url, base = '/') =>
url
// remove url origin
.replace(/^(https?:)?\/\/[^/]*/, '')
// remove site base
.replace(new RegExp(`^${base}`), '/');
export default {
name: 'DcloudSearchPage',
props: ['options'],
components: { NavbarLogo, Results, pagination, MainNavbarLink },
provide() {
return {
onSearchClose: this.onSearchClose,
};
},
data() {
return {
openSearch: false,
placeholder: '搜索内容',
snippetLength: 30,
searchValue: '',
category: Object.freeze([
{
text: '文档规范',
type: 'algolia',
},
{
text: '问答社区',
tag: 'ask',
type: 'server',
},
{
text: '插件市场',
tag: 'ext',
type: 'server',
},
{
text: 'DCloud 社区',
type: 'link',
link: 'https://ask.dcloud.net.cn/search/q-',
},
{
text: '原生开发文档',
type: 'link',
link: 'https://nativesupport.dcloud.net.cn/?s=',
},
{
text: 'HBuilderX 文档',
type: 'link',
link: 'https://hx.dcloud.net.cn/?s=',
},
]),
categoryIndex: 0,
resultList: [],
searchPage: 0, // 跳转页数
curHits: 0, // 当前搜索结果总条数
totalPage: 0, // 搜索结果总共页数
curPage: 1, // 当前页
pageSize: 0, // 每页条数
serverHtml: '',
};
},
computed: {
currentCategory() {
return this.category[this.categoryIndex];
},
isAlgolia() {
return this.currentCategory.type === 'algolia';
},
showPagination() {
return !!(this.resultList.length && this.totalPage > 1 && this.isAlgolia);
},
},
mounted() {
window.addEventListener('keydown', this.onKeyDown);
window.addEventListener('resize', this.initSnippetLength);
},
watch: {
resultList() {
this.$refs.pageContainer.scrollTop = 0;
},
openSearch(val) {
this.$nextTick(() => {
if (val) {
forbidScroll();
document.body.appendChild(this.$el);
this.$nextTick(() => this.$refs.searchInput.focus());
} else {
this.cancel();
forbidScroll(false);
document.body.removeChild(this.$el);
}
});
},
searchValue: debounce(function () {
this.resetSearchPage();
this.search();
}, 300),
},
methods: {
searchLink(link) {
return link + (link.includes('ask') ? Base64Encode(this.searchValue) : this.searchValue);
},
resetSearchPage() {
this.searchPage = 0;
},
research(curPage) {
this.searchPage = curPage - 1;
this.search();
},
search() {
if (!this.searchValue) return;
const { text, type } = this.currentCategory;
switch (type) {
case 'algolia':
this.searchByAlgolia(this.searchValue, this.searchPage).then(
({ hitsPerPage, nbHits, nbPages, page, hits }) => {
this.resultList = hits.map(item => {
const items = item.getItems();
return {
id: item.sourceId,
title: removeHighlightTags(items[0]),
items,
};
});
this.curHits = nbHits;
this.pageSize = hitsPerPage;
this.totalPage = nbPages;
this.curPage = page + 1;
}
);
break;
case 'server':
this.searchByServer(this.searchValue);
break;
}
},
searchByAlgolia(query = '', page = 0) {
const { searchParameters = {} } = this.options;
return searchClient(
Object.assign({}, this.options, {
query,
page,
snippetLength: this.snippetLength,
searchParameters: {
...searchParameters,
facetFilters: [`lang:${this.$lang}`].concat(searchParameters.facetFilters || []),
},
transformItems: items =>
items.map(item => {
// the `item.url` is full url with protocol and hostname
// so we have to transform it to vue-router path
return {
...item,
url: resolveRoutePathFromUrl(item.url, this.$site.base),
};
}),
})
);
},
searchByServer(query = '') {
const { tag } = this.currentCategory;
switch (tag) {
case 'ext':
postExt(query).then(({ html, hits }) => {
this.serverHtml = '';
this.serverHtml += html;
this.curHits = hits;
});
break;
case 'ask':
postAsk(query).then(({ html, hits }) => {
this.serverHtml = '';
this.serverHtml += html;
this.curHits = hits;
});
break;
default:
break;
}
},
mainNavLinkClass(index) {
return ['main-navbar-item', this.categoryIndex === index ? 'active' : ''];
},
initSnippetLength() {
if (window.matchMedia('(max-width: 980px)').matches) {
this.snippetLength = 20;
}
if (window.matchMedia('(max-width: 600px)').matches) {
this.snippetLength = 15;
}
},
switchCategory(index) {
this.categoryIndex = index;
this.research(1);
},
cancel() {
this.resultList.length = 0;
this.searchValue = '';
this.curHits = 0;
this.totalPage = 0;
},
onSearchOpen() {
this.openSearch = true;
},
onSearchClose() {
this.openSearch = false;
},
onKeyDown(event) {
if (
(event.keyCode === 27 && this.openSearch) ||
// The `Cmd+K` shortcut both opens and closes the modal.
(event.key === 'k' && (event.metaKey || event.ctrlKey)) ||
// The `/` shortcut opens but doesn't close the modal because it's
// a character.
(!isEditingContent(event) && event.key === '/' && !this.openSearch)
) {
event.preventDefault();
if (this.openSearch) {
this.onSearchClose();
} else {
this.onSearchOpen();
}
}
},
},
};
</script>
<style lang="stylus">
@import './index'
</style>
export default {
ext: {
"ret": 0,
"desc": "ok",
"data": [
{
"id": 7637,
"name": "map高德地图组件升级、离线设置个性化地图、样式文件 (ios、android)",
"version": "1.0.1",
"description": "nvue map 高德地图组件升级、离线个性化地图、离线设置样式文件、可使用nvue map 所有功能、免VIP使用个性化地图 QQ群:656731785",
"tags": "nvue map 高德地图组件升级、离线个性化地图、离线设置样式文件、可使用nvuemap所有功能、免VIP使用个性化地图",
"platforms": [
"Android",
"iOS"
],
"category_level1": "App原生插件",
"category_level2": "App原生插件",
"total_download": 2,
"average_rating": 0,
"support_count": 0,
"tagsArray": [
"nvue",
"map",
"高德地图组件升级、离线个性化地图、离线设置样式文件、可使用nvuemap所有功能、免VIP使用个性化地图"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=7637"
},
{
"id": 7457,
"name": "【猫优壁纸】创作者收益系统、支持抖音、快手、微信、QQ四版本(尊享版)",
"version": "3.6.8.1",
"description": "版本升级来袭带PC后台管理,内置壁纸下载、头像下载、视频下载等超多丰富内容,更有完善的积分系统和订单系统,并且包括QQ小程序、微信小程序、抖音小程序三版本",
"tags": "maoeus-wall-pro 好看的前端UI设计 PC后台管理系统 云开发 完善的积分系统",
"platforms": [
"aliyun",
"tcb"
],
"category_level1": "uniCloud",
"category_level2": "云端一体项目模板",
"total_download": 103,
"average_rating": 0,
"support_count": 0,
"tagsArray": [
"maoeus-wall-pro",
"好看的前端UI设计",
"PC后台管理系统",
"云开发",
"完善的积分系统"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=7457"
},
{
"id": 6998,
"name": "原生sqlite数据库",
"version": "1.0.1",
"description": "原生稳定sqlite数据库增删查改,分页查询,版本升级,事务控制,批量执行",
"tags": "sqlite数据库 增删查改 分页查询版本升级事务控制批量执行",
"platforms": [
"Android",
"iOS"
],
"category_level1": "App原生插件",
"category_level2": "App原生插件",
"total_download": 13,
"average_rating": 5,
"support_count": 0,
"tagsArray": [
"sqlite数据库",
"增删查改",
"分页查询版本升级事务控制批量执行"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=6998"
},
{
"id": 6139,
"name": "【猫优壁纸】创作者收益系统、支持抖音、微信、QQ三版本(运营版)",
"version": "3.6.8",
"description": "版本升级来袭带PC后台管理,内置壁纸下载、头像下载、视频下载等超多丰富内容,更有完善的积分系统和订单系统,并且包括QQ小程序、微信小程序、抖音小程序三版本",
"tags": "maoeus-wallpaper 好看的前端UI设计 PC后台管理系统 云开发 完善的积分系统",
"platforms": [
"aliyun",
"tcb"
],
"category_level1": "uniCloud",
"category_level2": "云端一体项目模板",
"total_download": 482,
"average_rating": 4.5,
"support_count": 0,
"tagsArray": [
"maoeus-wallpaper",
"好看的前端UI设计",
"PC后台管理系统",
"云开发",
"完善的积分系统"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=6139"
},
{
"id": 7453,
"name": "【猫优壁纸】单系统、积分系统、壁纸、头像、视频、表情包下载(基础版)",
"version": "3.6.6.3",
"description": "版本升级来袭带PC后台管理,内置壁纸下载、头像下载、视频下载等超多丰富内容,更有完善的积分系统和订单系统,并且包括QQ小程序、微信小程序、抖音小程序三版本",
"tags": "maoeus-wall-base 好看的前端UI设计 PC后台管理系统 云开发 完善的积分系统",
"platforms": [
"aliyun",
"tcb"
],
"category_level1": "uniCloud",
"category_level2": "云端一体项目模板",
"total_download": 35,
"average_rating": 0,
"support_count": 0,
"tagsArray": [
"maoeus-wall-base",
"好看的前端UI设计",
"PC后台管理系统",
"云开发",
"完善的积分系统"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=7453"
},
{
"id": 3243,
"name": "app更新升级-wgt包热更新-整包更新-遮盖原生导航及tabbar ",
"version": "1.2.0",
"description": "请求接口返回ios及Android线上版本信息,再与本机app版本对比,如需更新则弹出更新提示框-支持外部链接、整包、热更新,",
"tags": "更新 热更新 app 不支持NVUE APP升级",
"platforms": [],
"category_level1": "前端组件",
"category_level2": "通用组件",
"total_download": 2997,
"average_rating": 4.7,
"support_count": 3,
"tagsArray": [
"更新",
"热更新",
"app",
"不支持NVUE",
"APP升级"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=3243"
},
{
"id": 5579,
"name": "腾讯Bugly插件",
"version": "1.0.4",
"description": "腾讯Bugly插件,APP检查应用版本升级、运营统计、主动上报异常,bug奔溃闪退日志、设置用户ID、用户标签",
"tags": "腾讯Bugly bugly 版本升级 运营统计 bug奔溃闪退日志收集",
"platforms": [
"Android",
"iOS"
],
"category_level1": "App原生插件",
"category_level2": "App原生插件",
"total_download": 49,
"average_rating": 2.3,
"support_count": 0,
"tagsArray": [
"腾讯Bugly",
"bugly",
"版本升级",
"运营统计",
"bug奔溃闪退日志收集"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=5579"
},
{
"id": 7238,
"name": "腾讯bugly服务插件",
"version": "1.0.1",
"description": "一键接入接入bugly服务",
"tags": "bugly 升级",
"platforms": [
"Android"
],
"category_level1": "App原生插件",
"category_level2": "App原生插件",
"total_download": 4,
"average_rating": 0,
"support_count": 0,
"tagsArray": [
"bugly",
"升级"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=7238"
},
{
"id": 1371,
"name": "app版本升级原生弹框和进度提示(包含wgt升级)",
"version": "1.48",
"description": "app版本升级(包含热更新)弹框提示和进度显示,apk自动安装",
"tags": "版本升级 进度提示 app自动安装 弹框提示 wgt升级",
"platforms": [
"Android",
"iOS"
],
"category_level1": "App原生插件",
"category_level2": "App原生插件",
"total_download": 4967,
"average_rating": 4.9,
"support_count": 1,
"tagsArray": [
"版本升级",
"进度提示",
"app自动安装",
"弹框提示",
"wgt升级"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=1371"
},
{
"id": 4542,
"name": "升级中心 uni-upgrade-center - App",
"version": "0.3.2",
"description": "uni升级中心 - 客户端检查更新",
"tags": "uniCloud update 升级 wgt",
"platforms": [
"aliyun",
"tcb"
],
"category_level1": "uniCloud",
"category_level2": "云端一体页面模板",
"total_download": 11374,
"average_rating": 4.8,
"support_count": 3,
"tagsArray": [
"uniCloud",
"update",
"升级",
"wgt"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=4542"
}
]
},
ask: {
"code": 0,
"data": [
{
"url": "//ask.dcloud.net.cn/article/182",
"title": "App资源在线升级更新",
"content": " ... &amp;amp;&amp;amp;(wgtVer!=newVer)){\n\t\t\t\t\tdownWgt();\t// 下载&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;包\n\t\t\t\t}else{\n\t\t\t\t\tplus.nativeUI.alert(&amp;quot;无 ... ",
"type": "articles",
"comment_count": "212",
"view_count": "260871"
},
{
"url": "//ask.dcloud.net.cn/article/199",
"title": "App资源在线差量升级更新",
"content": " ... wgtu | 根节点 | | | |\t\n| appid | wgtu | 属性 | &lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;应用的appid | 是 |\n| basis | wgtu ... ",
"type": "articles",
"comment_count": "83",
"view_count": "76496"
},
{
"url": "//ask.dcloud.net.cn/article/17",
"title": "HBuilder升级失败或长时间无响应?",
"content": "如果装过其他eclipse插件,其&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;服务器可能连不上而导致报错。\n此时在工具-插件安装-手动安装eclipse插件-可用软件站点,取消其他插件的&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;地址。\n重新点击帮助-检查新版本即可。",
"type": "articles",
"comment_count": 0,
"view_count": "2500"
},
{
"url": "//ask.dcloud.net.cn/article/266",
"title": "增量升级",
"content": " ... ask.dcloud.net.cn/question/3388)\n\n**增量&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;的问题**\n增量、差量&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt; ... 。但是在使用H5 的增量&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;的时候遇到一个问题。 ... 是:\n当APP启动是出现&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;页面,用户点击增量 ... ",
"type": "articles",
"comment_count": "5",
"view_count": "3090"
},
{
"url": "//ask.dcloud.net.cn/article/273",
"title": "请Mac版用户近期不要升级MacOS 10.11beta3及10.11公测版",
"content": " ... 近期发布的公测版上,HBuilder也无法启动。\n**请大家近期不要&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;Mac 10.11beta3及10.11公测版,并等待苹果修复bug**\n详情 ... ",
"type": "articles",
"comment_count": "9",
"view_count": "3054"
}
],
"searchKeyword": "5Y2H57qn"
}
}
\ No newline at end of file
const xhr = new XMLHttpRequest();
const isProduction = process.env.NODE_ENV === "production"
const isMock = false
import mock from './mock'
function ajax(url = '', method = 'get',) {
return new Promise((resolve, reject) => {
if (!url) reject('url 不可为空')
xhr.open(method, url);
xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
console.log('this :>> ', this);
}
}
xhr.send()
})
}
export async function postExt(query) {
const base = isProduction ? '//ext.dcloud.net.cn' : '/ext'
let extRet
if (!isMock) {
const extRes = await ajax(base + '/search/json?query=' + encodeURIComponent(query))
extRet = JSON.parse(extRes);
} else {
extRet = mock.ext;
}
let extHtml = '';
let data = extRet.data;
if (extRet.ret === 0) {
for (let i = 0, len = data.length; i < len; i++) {
extHtml += _renderExt(data[i], query);
}
}
return {
html: extHtml,
hits: data.length
}
}
export async function postAsk(query) {
const base = isProduction ? '//ask.dcloud.net.cn' : '/ask'
let ret
if (!isMock) {
const res = await ajax(base + '/search/ajax/search_result/search_type-doc__q-' + query + '__page-1')
if (!res) {
return;
}
ret = JSON.parse(res);
} else {
ret = mock.ask
}
if (ret.code !== 0) {
checkEmpty()
return;
}
var data = ret.data;
var askHtml = '';
data.forEach(function (item) {
askHtml += _renderPost(item, query);
});
return {
html: askHtml,
hits: data.length
}
}
function _renderExt(ext, keyword) {
return `<div class="matching-post">
<a href="${ext.url}" target="_blank">
<div class="post-wrapper">
<p class="aw-text">
<span class="post-tag">插件</span>
</p>
<h2>${_handleHTMLString(ext.name, keyword)}</h2>
</div>
<p>${ext.total_download}次下载</p>
<p>${_handleHTMLString(ext.description, keyword)}</p>
</a>
</div>`
}
function _renderPost(post, value) {
var html = '';
var commentText = '';
var tagName = '规范';
// 1,问题;2,文章;默认是规范。
switch (post.type) {
case 'questions':
tagName = '问题';
break;
case 'articles':
tagName = '文章';
break;
}
if (!!value) {
post.title = _handleHTMLString(post.title, value);
post.content = _handleHTMLString(post.content, value);
}
html += `<div class="matching-post">
<a href="${post.url}" target="_blank"><div class="post-wrapper">
<p class="aw-text"><span class="post-tag">${tagName}</span></p>
<h2>${post.title}</h2></div>`
/* html += '<div class="matching-post">\n';
html += `<a href="${post.url}" target="_blank"><div class="post-wrapper">`;
html += `<p class="aw-text"><span class="post-tag">${tagName}</span></p>`
html += `\n<h2>${post.title}</h2></div>`; */
if (!!value) {
commentText = post.type === 'questions' ? '回复' : '评论';
html += `<p>${post.comment_count}${commentText}<span class="aw-text-space">-</span>${post.view_count}次浏览</p>`;
}
html += `\n<p>${post.content}</p>\n</a>\n</div>`;
return html;
}
function _handleHTMLString(dataString, keyword) {
var keywordReg = new RegExp(
keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'),
'gi'
);
var tagStartReg = new RegExp(
'&lt;span style=\'font-weight:bold;color:red\'&gt;',
'g'
);
var tagEndReg = new RegExp(
'&lt;/span&gt;',
'g'
);
return dataString
.replace(tagStartReg, '')
.replace(tagEndReg, '')
.replace(keywordReg, ("<em class=\"search-keyword\">" + keyword + "</em>"));
};
\ No newline at end of file
import algoliasearch from 'algoliasearch/dist/algoliasearch-lite.esm.browser';
import { removeHighlightTags, groupBy } from '../../util'
let searchClient
function createSearchClient(appId, apiKey) {
if (searchClient) return searchClient
searchClient = algoliasearch(appId, apiKey);
searchClient.addAlgoliaAgent('dcloudsearch', '1.0.0');
return searchClient
}
export function search({ query, indexName, appId, apiKey, searchParameters = {}, snippetLength = 0, transformItems = () => { }, ...args }) {
return createSearchClient(appId, apiKey)
.search([
{
query,
indexName,
params: {
attributesToRetrieve: [
'hierarchy.lvl0',
'hierarchy.lvl1',
'hierarchy.lvl2',
'hierarchy.lvl3',
'hierarchy.lvl4',
'hierarchy.lvl5',
'hierarchy.lvl6',
'content',
'type',
'url',
],
attributesToSnippet: [
`hierarchy.lvl1:${snippetLength}`,
`hierarchy.lvl2:${snippetLength}`,
`hierarchy.lvl3:${snippetLength}`,
`hierarchy.lvl4:${snippetLength}`,
`hierarchy.lvl5:${snippetLength}`,
`hierarchy.lvl6:${snippetLength}`,
`content:${snippetLength}`,
],
snippetEllipsisText: '',
highlightPreTag: '<mark>',
highlightPostTag: '</mark>',
hitsPerPage: 20,
...searchParameters,
...args,
},
},
])
.catch((error) => {
throw error;
})
.then(({ results }) => {
const { hits, hitsPerPage, nbHits, nbPages, page } = results[0];
const sources = groupBy(hits, (hit) => removeHighlightTags(hit));
return {
hitsPerPage, nbHits, nbPages, page,
hits: Object.values(sources).map(
(items, index) => {
return {
sourceId: `hits${index}`,
onSelect({ item, event }) {
// saveRecentSearch(item);
// if (!event.shiftKey && !event.ctrlKey && !event.metaKey) {
// onClose();
// }
},
getItemUrl({ item }) {
return item.url;
},
getItems() {
return Object.values(
groupBy(items, (item) => item.hierarchy.lvl1)
)
.map(transformItems)
.map((groupedHits) =>
groupedHits.map((item) => {
return {
...item,
__docsearch_parent:
item.type !== 'lvl1' &&
groupedHits.find(
(siblingItem) =>
siblingItem.type === 'lvl1' &&
siblingItem.hierarchy.lvl1 ===
item.hierarchy.lvl1
),
};
})
).flat();
},
};
}
)
}
});
}
\ No newline at end of file
......@@ -312,6 +312,6 @@
};
</script>
<style lang="stylus">
<style lang="stylus" scoped>
@import '../styles/footer.styl'
</style>
......@@ -3,29 +3,7 @@
<div class="main-navbar">
<!-- <SidebarButton @toggle-sidebar="$emit('toggle-sidebar')" /> -->
<a
href="https://www.dcloud.io"
class="home-link"
>
<img
v-if="$site.themeConfig.logo"
class="logo"
:src="$withBase($site.themeConfig.logo)"
:alt="$siteTitle"
>
<img
v-if="$site.themeConfig.titleLogo"
class="title-logo can-hide"
:src="$withBase($site.themeConfig.titleLogo)"
:alt="$siteTitle"
>
<span
v-else-if="$siteTitle"
ref="siteName"
class="site-name"
:class="{ 'can-hide': $site.themeConfig.logo }"
>{{ $siteTitle }}</span>
</a>
<NavbarLogo />
<div class="main-navbar-links can-hide">
<template v-for="(item, index) in customNavBar">
......@@ -57,6 +35,7 @@
} : {}"
>
<a class="switch-version" href="javascript:void(0)" @click="switchVersion">回到旧版</a>
<DcloudSearchPage ref="dcloudSearchPage" v-if="isAlgoliaSearch" :options="algolia"/>
<AlgoliaSearchBox
v-if="isAlgoliaSearch"
:options="algolia"
......@@ -82,6 +61,8 @@ import SearchBox from './SearchBox'
import SidebarButton from '@theme/components/SidebarButton.vue'
import NavLinks from '@theme/components/NavLinks.vue'
import MainNavbarLink from './MainNavbarLink.vue';
import NavbarLogo from './NavbarLogo.vue';
import DcloudSearchPage from './DcloudSearchPage';
import navInject from '../mixin/navInject';
import { forbidScroll, os } from '../util';
......@@ -95,7 +76,9 @@ export default {
NavLinks,
MainNavbarLink,
SearchBox,
AlgoliaSearchBox
AlgoliaSearchBox,
NavbarLogo,
DcloudSearchPage
},
data () {
......
<template>
<a href="https://www.dcloud.io" class="home-link">
<img
v-if="$site.themeConfig.logo"
class="logo"
:src="$withBase($site.themeConfig.logo)"
:alt="$siteTitle"
/>
<img
v-if="$site.themeConfig.titleLogo"
class="title-logo can-hide"
:src="$withBase($site.themeConfig.titleLogo)"
:alt="$siteTitle"
/>
<span
v-else-if="$siteTitle"
ref="siteName"
class="site-name"
:class="{ 'can-hide': $site.themeConfig.logo }"
>
{{ $siteTitle }}
</span>
</a>
</template>
......@@ -4,6 +4,7 @@
:class="pageClasses"
@touchstart="onTouchStart"
@touchend="onTouchEnd"
@keydown.ctrl="openSearch = true"
>
<Navbar
v-if="shouldShowNavbar"
......
......@@ -3,4 +3,5 @@ $accentColor = #42b983
$contentWidth = 1200px
$navbarHeight = 9rem
$navbar-sub-navbar-height = 5rem
$navbar-background-color = #f7f7f7
\ No newline at end of file
$navbar-background-color = #f7f7f7
$search-container-color = #f5f6f7
\ No newline at end of file
var validBitList = [
[7],
[5, 6],
[4, 6, 6],
[3, 6, 6, 6],
[2, 6, 6, 6, 6],
[1, 6, 6, 6, 6, 6]
]
var otherByteBase = 1 << 7
var b64Info = new Array(6)
for (var i = 0; i < validBitList.length; i++) {
var validBit = validBitList[i]
var firstByteBase
if (i === 0) {
firstByteBase = 0
}
var fillLength = validBit[0] + 1
firstByteBase = 255 >> fillLength << fillLength
b64Info[i] = {
validBit,
firstByteBase,
otherByteBase,
maxValue: Math.pow(2, sum(validBit)) - 1 // 移位会溢出,使用Math.pow计算
}
}
function sum(arr) {
return arr.reduce(function (total, value) {
return total + value
}, 0)
}
function Encoder() {
this.remainder = 0
this.remainderBit = 0
this.utf8ArrLength = 0
this.result = ''
}
Encoder.prototype.push = function (utf8Code) {
this.utf8ArrLength++
var remainderMoveBit = (6 - this.remainderBit)
this.remainderBit = 8 - remainderMoveBit
var b64Value1 = this.remainder << remainderMoveBit
var b64Value2 = utf8Code >> this.remainderBit
var b64Value = b64Value1 + b64Value2
this.remainder = utf8Code - (b64Value2 << this.remainderBit)
this.result += b64CodeToString(b64Value)
if (this.remainderBit === 6) {
this.result += b64CodeToString(this.remainder)
this.remainder = 0
this.remainderBit = 0
}
}
Encoder.prototype.flush = function () {
if (this.remainderBit) {
var b64Value = this.remainder << (6 - this.remainderBit)
this.result += b64CodeToString(b64Value)
}
var eqLength = (3 - (this.utf8ArrLength % 3)) % 3
this.result += '='.repeat(eqLength)
}
function charCodeToUtf8(code) {
var lengthIndex
for (var i = 0; i < b64Info.length; i++) {
var maxValue = b64Info[i].maxValue;
if (code <= maxValue) {
lengthIndex = i
break;
}
}
if (lengthIndex === undefined) {
throw new Error('invalid char code')
}
var {
validBit,
firstByteBase,
otherByteBase,
} = b64Info[lengthIndex]
var result = []
for (var i = validBit.length - 1; i >= 0; i--) {
var base = i === 0 ? firstByteBase : otherByteBase
var tempCode = code >>> validBit[i]
result.unshift(base + code - (tempCode << validBit[i]))
code = tempCode
}
return result
}
export function Base64Encode(str) {
// 一次循环计算出结果,减少内存占用
var encoder = new Encoder()
for (var i = 0; i < str.length; i++) {
var charCode = str.charCodeAt(i);
var utf8Arr = charCodeToUtf8(charCode)
utf8Arr.forEach(function (item) {
encoder.push(item)
});
}
encoder.flush()
return encoder.result
}
function b64CodeToString(code) {
return String.fromCharCode(uint6ToB64(code))
}
/**
* 将base64 code转换为字符对应的char code
*/
function uint6ToB64(nUint6) {
return nUint6 < 26 ?
nUint6 + 65 :
nUint6 < 52 ?
nUint6 + 71 :
nUint6 < 62 ?
nUint6 - 4 :
nUint6 === 62 ?
43 :
nUint6 === 63 ?
47 :
65;
}
\ No newline at end of file
import Vue from 'vue';
export * from './searchUtils';
export * from './base64Encode';
export const isServer = Vue.prototype.$isServer
export const hashRE = /#.*$/
export const extRE = /\.(md|html)$/
......@@ -287,4 +290,17 @@ export const BaiduStat = () => {
hm.src = "https://hm.baidu.com/hm.js?fe3b7a223fc08c795f0f4b6350703e6f";
const s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
}
export function debounce(fn, delay) {
let timeout
const newFn = function () {
clearTimeout(timeout)
const timerFn = () => fn.apply(this, arguments)
timeout = setTimeout(timerFn, delay)
}
newFn.cancel = function () {
clearTimeout(timeout)
}
return newFn
}
\ No newline at end of file
export function groupBy(values, predicate) {
return values.reduce((acc, item) => {
const key = predicate(item);
if (!acc.hasOwnProperty(key)) {
acc[key] = [];
}
// We limit each section to show 5 hits maximum.
// This acts as a frontend alternative to `distinct`.
if (acc[key].length < 5) {
acc[key].push(item);
}
return acc;
}, {});
}
const regexHighlightTags = /(<mark>|<\/mark>)/g;
const regexHasHighlightTags = RegExp(regexHighlightTags.source);
export function removeHighlightTags(hit) {
const internalDocSearchHit = hit
if (!internalDocSearchHit.__docsearch_parent && !hit._highlightResult) {
return hit.hierarchy.lvl0;
}
const { value } =
(internalDocSearchHit.__docsearch_parent
? internalDocSearchHit.__docsearch_parent?._highlightResult?.hierarchy
?.lvl0
: hit._highlightResult?.hierarchy?.lvl0) || {};
return value && regexHasHighlightTags.test(value)
? value.replace(regexHighlightTags, '')
: value;
}
export function isEditingContent(event) {
const element = event.target;
const tagName = element.tagName;
return (
element.isContentEditable ||
tagName === 'INPUT' ||
tagName === 'SELECT' ||
tagName === 'TEXTAREA'
);
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册