Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DCloud
unidocs-zh
提交
720efbf6
unidocs-zh
项目概览
DCloud
/
unidocs-zh
通知
3323
Star
107
Fork
845
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
102
列表
看板
标记
里程碑
合并请求
82
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
unidocs-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
102
Issue
102
列表
看板
标记
里程碑
合并请求
82
合并请求
82
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
720efbf6
编写于
3月 17, 2022
作者:
D
DCloud_LXH
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
wip: search page
上级
73bf1739
变更
13
隐藏空白更改
内联
并排
Showing
13 changed file
with
752 addition
and
321 deletion
+752
-321
docs/.vuepress/config.js
docs/.vuepress/config.js
+1
-1
docs/.vuepress/theme/components/AlgoliaSearchBox.vue
docs/.vuepress/theme/components/AlgoliaSearchBox.vue
+36
-127
docs/.vuepress/theme/components/DcloudSearchPage/components/Result.vue
...s/theme/components/DcloudSearchPage/components/Result.vue
+122
-0
docs/.vuepress/theme/components/DcloudSearchPage/components/Results.vue
.../theme/components/DcloudSearchPage/components/Results.vue
+42
-0
docs/.vuepress/theme/components/DcloudSearchPage/components/pagination.vue
...eme/components/DcloudSearchPage/components/pagination.vue
+155
-0
docs/.vuepress/theme/components/DcloudSearchPage/index.styl
docs/.vuepress/theme/components/DcloudSearchPage/index.styl
+129
-0
docs/.vuepress/theme/components/DcloudSearchPage/index.vue
docs/.vuepress/theme/components/DcloudSearchPage/index.vue
+192
-143
docs/.vuepress/theme/components/DcloudSearchPage/searchClient.js
...uepress/theme/components/DcloudSearchPage/searchClient.js
+42
-40
docs/.vuepress/theme/components/Navbar.vue
docs/.vuepress/theme/components/Navbar.vue
+4
-1
docs/.vuepress/theme/layouts/Layout.vue
docs/.vuepress/theme/layouts/Layout.vue
+2
-8
docs/.vuepress/theme/styles/palette.styl
docs/.vuepress/theme/styles/palette.styl
+2
-1
docs/.vuepress/theme/util/index.js
docs/.vuepress/theme/util/index.js
+13
-0
docs/.vuepress/theme/util/searchUtils.js
docs/.vuepress/theme/util/searchUtils.js
+12
-0
未找到文件。
docs/.vuepress/config.js
浏览文件 @
720efbf6
...
...
@@ -36,7 +36,7 @@ const config = {
apiKey
:
'
2fdcc4e76c8e260671ad70065e60b2e7
'
,
indexName
:
'
zh-uniapp
'
,
appId
:
'
PQIR5NL8CZ
'
,
searchParameters
:
{
hitsPerPage
:
8
0
}
searchParameters
:
{
hitsPerPage
:
4
0
}
}
},
markdown
:
{
...
...
docs/.vuepress/theme/components/AlgoliaSearchBox.vue
浏览文件 @
720efbf6
<
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
>
...
...
docs/.vuepress/theme/components/DcloudSearchPage/components/Result.vue
0 → 100644
浏览文件 @
720efbf6
<
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 4px
display flex
padding-bottom 4px
position relative
a
background var(--docsearch-hit-background)
border-radius 4px
box-shadow var(--docsearch-hit-shadow)
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
>
docs/.vuepress/theme/components/DcloudSearchPage/components/Results.vue
0 → 100644
浏览文件 @
720efbf6
<
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-Hits mark {
background: none;
color: $accentColor;
}
.DocSearch-Hit-source {
background-color $search-container-color;
color: $accentColor;
}
</
style
>
docs/.vuepress/theme/components/DcloudSearchPage/components/pagination.vue
0 → 100644
浏览文件 @
720efbf6
<
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
>
docs/.vuepress/theme/components/DcloudSearchPage/index.styl
0 → 100644
浏览文件 @
720efbf6
$svg-color = #b1b2b3
$svg-hover-color = #9b9b9b
#search-container
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
.search-category
.navbar
border none
.main-navbar
box-shadow none
.main-navbar-links
width 100%
padding 0
.main-navbar-item
padding 0 6%
.result-number
display flex
justify-content center
margin-top 20px
font-size 20px
.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
\ No newline at end of file
docs/.vuepress/theme/components/DcloudSearchPage/index.vue
浏览文件 @
720efbf6
<
template
>
<div
id=
"search-c
ontainer"
>
<div
v-if=
"openSearch"
id=
"search-container"
ref=
"pageC
ontainer"
>
<div
class=
"search-navbar"
>
<div
class=
"search-navbar-wrap"
>
<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
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
class=
"sub-navbar"
>
<div
class=
"search-wrap"
>
<div
class=
"input-wrap"
>
<input
class=
"search-input"
:placeholder=
"placeholder"
type=
"text"
v-model=
"searchValue"
/>
<span
class=
"search-input-btn"
>
<button
@
click=
"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>
</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=
"search"
v-model=
"searchValue"
/>
<span
class=
"search-input-btn"
>
<button
@
click=
"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"
>
<a
href=
"javascript:;"
@
click=
"categoryIndex = index"
>
{{
item
.
text
}}
</a>
</div>
</
template
>
</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"
>
<a
href=
"javascript:;"
@
click=
"categoryIndex = index"
>
{{
item
.
text
}}
</a>
</div>
</
template
>
</div>
</div>
</div>
...
...
@@ -55,14 +56,38 @@
</div>
</div>
<div
class=
"search-result"
></div>
<div
class=
"result-number"
>
<span>
共{{ curHits }}个相关结果
</span>
</div>
<div
class=
"search-result"
>
<div
class=
"result-wrap"
>
<
template
v-if=
"resultList.length"
>
<template
v-for=
"item in resultList"
>
<Results
:key=
"item.id"
:title=
"item.title"
:results=
"item.items"
/>
</
template
>
</template>
</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
{
search
as
searchClient
}
from
'
./searchClient
'
;
import
{
forbidScroll
}
from
'
../../util
'
;
import
{
forbidScroll
,
removeHighlightTags
,
debounce
,
isEditingContent
}
from
'
../../util
'
;
const
resolveRoutePathFromUrl
=
(
url
,
base
=
'
/
'
)
=>
url
...
...
@@ -76,44 +101,114 @@
props
:
[
'
options
'
],
components
:
{
NavbarLogo
},
components
:
{
NavbarLogo
,
Results
,
pagination
},
provide
()
{
return
{
onSearchClose
:
this
.
onSearchClose
,
};
},
data
()
{
return
{
openSearch
:
false
,
placeholder
:
'
搜索内容
'
,
snippetLength
:
1
0
,
snippetLength
:
3
0
,
searchValue
:
''
,
category
:
Object
.
freeze
([
{
text
:
'
uni-app
'
,
},
{
text
:
'
uniCloud
'
,
text
:
'
uni
'
,
type
:
'
algolia
'
,
},
{
text
:
'
问答社区
'
,
type
:
'
server
'
,
},
{
text
:
'
插件市场
'
,
type
:
'
server
'
,
},
]),
categoryIndex
:
0
,
resultList
:
[],
searchPage
:
0
,
// 跳转页数
curHits
:
0
,
// 当前搜索条数
totalPage
:
0
,
// 搜索结果总共条数
curPage
:
1
,
// 当前页
pageSize
:
0
,
// 每页条数
};
},
computed
:
{
showPagination
()
{
return
!!
(
this
.
resultList
.
length
&&
this
.
totalPage
>
1
);
},
},
mounted
()
{
this
.
$nextTick
(
forbidScroll
);
window
.
addEventListener
(
'
keydown
'
,
this
.
onKeyDown
);
window
.
addEventListener
(
'
resize
'
,
this
.
initSnippetLength
);
},
watch
:
{
resultList
()
{
this
.
$refs
.
pageContainer
.
scrollTop
=
0
;
},
const
isMobileMediaQuery
=
window
.
matchMedia
(
'
(max-width: 750px)
'
);
openSearch
(
val
)
{
this
.
$nextTick
(()
=>
{
if
(
val
)
{
this
.
$nextTick
(
forbidScroll
);
document
.
body
.
appendChild
(
this
.
$el
);
this
.
$nextTick
(()
=>
this
.
$refs
.
searchInput
.
focus
());
}
else
{
this
.
cancel
();
forbidScroll
(
false
);
document
.
body
.
removeChild
(
this
.
$el
);
// window.removeEventListener('keydown', this.onKeyDown);
}
});
},
if
(
isMobileMediaQuery
.
matches
)
{
this
.
snippetLength
=
5
;
}
searchValue
:
debounce
(
function
()
{
this
.
searchPage
=
0
;
this
.
search
();
},
300
),
},
methods
:
{
research
(
curPage
)
{
this
.
searchPage
=
curPage
-
1
;
this
.
search
();
},
search
()
{
this
.
searchByAlgolia
(
this
.
searchValue
);
if
(
!
this
.
searchValue
)
return
;
const
{
text
,
type
}
=
this
.
category
[
this
.
categoryIndex
];
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
'
:
console
.
log
(
'
从服务端搜索
'
);
break
;
}
},
searchByAlgolia
(
query
=
''
,
page
=
0
)
{
...
...
@@ -143,100 +238,54 @@
mainNavLinkClass
(
index
)
{
return
[
'
main-navbar-item
'
,
this
.
categoryIndex
===
index
?
'
active
'
:
''
];
},
},
};
</
script
>
<
style
lang=
"stylus"
>
$svg-color = #b1b2b3;
$svg-hover-color = #9b9b9b;
#search-container{
position fixed
width 100vw
height 100vh
left 0
top 0
z-index 200
background-color #fff
.sub-navbar {
width: 80%;
max-width: 960px;
min-width: 720px;
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;
.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;
}
}
}
initSnippetLength
()
{
if
(
window
.
matchMedia
(
'
(max-width: 980px)
'
).
matches
)
{
this
.
snippetLength
=
20
;
}
.search-input {
width: 100%;
height: 56px;
font-size: 16px;
border: none;
box-sizing: border-box;
outline: none;
padding: 1px 10px;
border-radius: 4px;
if
(
window
.
matchMedia
(
'
(max-width: 600px)
'
).
matches
)
{
this
.
snippetLength
=
15
;
}
},
.search-input-btn {
height: 56px;
}
}
cancel
()
{
this
.
resultList
.
length
=
0
;
this
.
searchValue
=
''
;
this
.
curHits
=
0
;
this
.
totalPage
=
0
;
},
.search-category {
onSearchOpen
()
{
this
.
openSearch
=
true
;
},
onSearchClose
()
{
this
.
openSearch
=
false
;
},
.main-navbar-links {
width: 100%;
padding: 0;
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
();
.main-navbar-item {
padding: 0 6%;
if
(
this
.
openSearch
)
{
this
.
onSearchClose
();
}
else
{
this
.
onSearchOpen
();
}
}
}
},
},
};
</
script
>
}
}
<
style
lang=
"stylus"
>
@import './index'
</
style
>
docs/.vuepress/theme/components/DcloudSearchPage/searchClient.js
浏览文件 @
720efbf6
...
...
@@ -42,8 +42,8 @@ export function search({ query, indexName, appId, apiKey, searchParameters = {},
highlightPreTag
:
'
<mark>
'
,
highlightPostTag
:
'
</mark>
'
,
hitsPerPage
:
20
,
...
args
,
...
searchParameters
,
...
args
,
},
},
])
...
...
@@ -51,46 +51,48 @@ export function search({ query, indexName, appId, apiKey, searchParameters = {},
throw
error
;
})
.
then
(({
results
})
=>
{
const
{
hits
,
nbHits
}
=
results
[
0
];
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);
return
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
();
},
};
}
);
// 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
docs/.vuepress/theme/components/Navbar.vue
浏览文件 @
720efbf6
...
...
@@ -35,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"
...
...
@@ -61,6 +62,7 @@ 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
'
;
...
...
@@ -75,7 +77,8 @@ export default {
MainNavbarLink
,
SearchBox
,
AlgoliaSearchBox
,
NavbarLogo
NavbarLogo
,
DcloudSearchPage
},
data
()
{
...
...
docs/.vuepress/theme/layouts/Layout.vue
浏览文件 @
720efbf6
...
...
@@ -4,6 +4,7 @@
:class=
"pageClasses"
@
touchstart=
"onTouchStart"
@
touchend=
"onTouchEnd"
@
keydown.ctrl=
"openSearch = true"
>
<Navbar
v-if=
"shouldShowNavbar"
...
...
@@ -42,8 +43,6 @@
<Footer
/>
</
template
>
</Page>
<DcloudSearchPage
:options=
"algolia"
/>
</div>
</template>
...
...
@@ -54,7 +53,6 @@ import Page from '@theme/components/Page.vue'
import
Sidebar
from
'
@theme/components/Sidebar.vue
'
import
Footer
from
'
@theme/components/Footer.vue
'
;
import
SiderBarBottom
from
'
../components/SiderBarBottom.vue
'
;
import
DcloudSearchPage
from
'
../components/DcloudSearchPage
'
;
import
{
resolveSidebarItems
,
forbidScroll
,
BaiduStat
}
from
'
../util
'
import
navProvider
from
'
../mixin/navProvider
'
;
...
...
@@ -67,8 +65,7 @@ export default {
Sidebar
,
Navbar
,
Footer
,
SiderBarBottom
,
DcloudSearchPage
SiderBarBottom
},
data
()
{
return
{
...
...
@@ -118,9 +115,6 @@ export default {
},
userPageClass
]
},
algolia
()
{
return
this
.
$themeLocaleConfig
.
algolia
||
this
.
$site
.
themeConfig
.
algolia
||
{}
}
},
mounted
()
{
...
...
docs/.vuepress/theme/styles/palette.styl
浏览文件 @
720efbf6
...
...
@@ -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
docs/.vuepress/theme/util/index.js
浏览文件 @
720efbf6
...
...
@@ -289,4 +289,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
docs/.vuepress/theme/util/searchUtils.js
浏览文件 @
720efbf6
...
...
@@ -37,3 +37,15 @@ export function removeHighlightTags(hit) {
?
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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录