提交 0c973c26 编写于 作者: D DCloud_LXH

Merge branch 'vuepress'

dist
\ No newline at end of file
<template>
<div class="banner">
<div class="slider">
<span class="slider-btn slider-btn-left"></span>
<span class="slider-btn slider-btn-right"></span>
<div class="slider-group">
<template v-for="item in images">
<div class="slider-item" :key="item">
<img :src="item" />
</div>
</template>
</div>
</div>
</div>
</template>
<script>
var sliderTime;
export default {
data() {
return {
images: [
'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/41136990-4f3e-11eb-8ff1-d5dcf8779628.png',
'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/3ecf6d00-4f3e-11eb-8ff1-d5dcf8779628.png',
'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/3df62400-4f3e-11eb-8ff1-d5dcf8779628.png',
'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/3f872440-4f3e-11eb-8a36-ebb87efcf8c0.png',
'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/40596860-4f3e-11eb-bdc1-8bd33eb6adaa.png',
],
};
},
mounted() {
this.StartBanner();
},
beforeDestroy() {
clearInterval(sliderTime);
},
methods: {
StartBanner() {
var banner = document.querySelector('.banner'),
slider = document.querySelector('.slider-group'),
sliderItems = document.querySelectorAll('.slider-item'),
sliderLength = sliderItems.length;
var bannerWidth = null,
index = 1; //slider下标
var arrowLeft = document.querySelector('.slider-btn-left'),
arrowRight = document.querySelector('.slider-btn-right');
//创建dots
var sliderDots = document.createElement('div');
sliderDots.className = 'slider-dots';
var dots = '<span class="dot active" data-num="0"></span>';
for (var i = 1; i < sliderLength; i++) {
dots += '<span class="dot" data-num="' + i + '"></span>';
}
sliderDots.innerHTML = dots;
document.querySelector('.slider').appendChild(sliderDots);
//在第一个前、最后一个后各加一个item
var last_item = document.createElement('div'),
next_item = document.createElement('div');
last_item.className = 'slider-item';
last_item.innerHTML = sliderItems[sliderItems.length - 1].innerHTML;
slider.insertBefore(last_item, sliderItems[0]);
next_item.className = 'slider-item';
next_item.innerHTML = sliderItems[0].innerHTML;
slider.appendChild(next_item);
sliderItems = document.querySelectorAll('.slider-item');
function setSlider() {
bannerWidth = banner.offsetWidth;
for (var i = 0, length = sliderItems.length; i < length; i++) {
sliderItems[i].style.width = bannerWidth + 'px';
}
slider.style.width = sliderItems.length * bannerWidth + 'px';
slider.style.transition = 'transform 0ms';
slider.style.transform = 'translate(' + -index * bannerWidth + 'px, 0px)';
}
setSlider();
window.onresize = setSlider;
sliderTime = setInterval(sliderStart, 5000);
function sliderStart() {
//开始轮播)
/* if(!~location.pathname.indexOf($docsify.banner)){
clearInterval(sliderTime);
return;
} */
index += 1;
if (index < 0 || index > sliderLength + 1) {
index = index < 0 ? 0 : sliderLength + 1;
}
slider.style.transition = 'transform 300ms';
document.querySelector('.active.dot').classList.remove('active');
var dotIndex = index > sliderLength ? 0 : index < 1 ? sliderLength - 1 : index - 1;
sliderDots.children[dotIndex].classList.add('active');
slider.style.transform = 'translate(' + -index * bannerWidth + 'px, 0px)';
setTimeout(function () {
if (index > sliderLength || index < 1) {
index = index > sliderLength ? 1 : sliderLength;
slider.style.transition = 'transform 0ms';
slider.style.transform = 'translate(' + -index * bannerWidth + 'px, 0px)';
}
}, 300);
}
var mouseClearSlider = false;
sliderDots.addEventListener('mouseover', function (e) {
showArrow();
if (e.target.tagName === 'SPAN') {
mouseClearSlider = true;
clearInterval(sliderTime);
if (e.target.className === 'dot') {
slider.style.transition = 'transform 300ms';
document.querySelector('.active.dot').classList.remove('active');
e.target.classList.add('active');
index = Number(e.target.dataset.num) + 1;
slider.style.transform = 'translate(' + -index * bannerWidth + 'px, 0px)';
}
return;
}
if (mouseClearSlider) {
mouseClearSlider = false;
clearInterval(sliderTime);
sliderTime = setInterval(sliderStart, 5000);
}
});
sliderDots.addEventListener('mouseout', function (e) {
hideArrow();
if (mouseClearSlider) {
mouseClearSlider = false;
clearInterval(sliderTime);
sliderTime = setInterval(sliderStart, 5000);
}
});
// 处理 banner 的两个箭头
document.querySelector('.slider').addEventListener('mouseover', showArrow);
document.querySelector('.slider').addEventListener('mouseout', hideArrow);
arrowLeft.addEventListener('mouseover', showArrow);
arrowLeft.addEventListener('mouseout', hideArrow);
arrowRight.addEventListener('mouseover', showArrow);
arrowRight.addEventListener('mouseout', hideArrow);
function showArrow() {
//显示箭头
arrowLeft.style.display = 'block';
arrowRight.style.display = 'block';
// var scroll_left = document.documentElement.scrollLeft;
// arrowLeft.style.left = scroll_left + "px";
// arrowRight.style.right = document.documentElement.scrollWidth - document.documentElement.clientWidth - scroll_left +
// 'px';
}
function hideArrow() {
//隐藏箭头
arrowLeft.style.display = 'none';
arrowRight.style.display = 'none';
}
arrowLeft.addEventListener('click', function () {
index -= 2;
clearInterval(sliderTime);
sliderStart();
sliderTime = setInterval(sliderStart, 5000);
});
arrowRight.addEventListener('click', function () {
clearInterval(sliderTime);
sliderStart();
sliderTime = setInterval(sliderStart, 5000);
});
},
},
};
</script>
<style>
/* banner */
.banner {
width: 100%;
margin: 0 auto;
overflow: hidden;
}
.banner .slider {
position: relative;
width: 100%;
overflow: hidden;
}
.banner .slider-btn {
position: absolute;
cursor: pointer;
width: 41px;
height: 69px;
top: 50%;
transform: translateY(-50%);
-webkit-transform: translateY(-50%);
z-index: 20;
display: none;
background-image: url(https://vkceyugu.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/d2c41062-9e93-478f-9c06-06778b0f2c84.png);
}
.banner .slider-btn.slider-btn-left {
left: 0;
}
.banner .slider-btn.slider-btn-right {
right: 0;
background-position-x: 41px;
}
.banner .slider-item {
float: left;
width: 100%;
}
.banner .slider .slider-dots {
display: none;
position: absolute;
line-height: 0;
left: 50%;
bottom: 5px;
transform: translateX(-50%);
-webkit-transform: translateX(-50%);
text-align: center;
font-size: 0;
}
.banner .slider .dot {
display: inline-block;
margin: 0 5px;
width: 10px;
height: 10px;
border-radius: 50%;
background: #ccc;
cursor: pointer;
}
.banner .slider .dot.active {
width: 30px;
border-radius: 10px;
background: rgb(225, 114, 0);
}
</style>
<template>
<div></div>
</template>
<script>
export default {
data() {
return {
contentFrame: [],
};
},
mounted() {
if (this.$isServer) return;
const visibleHeight =
document.documentElement.clientHeight - document.querySelector('.sub-navbar').clientHeight;
const contentRef = document.querySelector('.page .theme-default-content');
const renderUl = () => {
const contentChildren = contentRef.children;
[...contentChildren].forEach((child, index) => {
if (child.nodeName === 'UL') {
const ulHeight = child.clientHeight;
const isVisible = visibleHeight + window.scrollY > child.offsetTop - 500;
child.style.height = `${ulHeight}px`;
if (!isVisible) {
const _ul = document.createDocumentFragment();
[...child.children].forEach(item => _ul.appendChild(item));
(!this.contentFrame[index] || !this.contentFrame[index].children.length) &&
(this.contentFrame[index] = _ul);
} else {
if (this.contentFrame[index]) {
[...this.contentFrame[index].children].forEach(item => child.appendChild(item));
}
}
}
});
};
if (contentRef) {
contentRef.style.height = contentRef.clientHeight;
renderUl();
window.addEventListener('scroll', renderUl);
}
},
};
</script>
const { slugify } = require('@vuepress/shared-utils')
const translatePlugin = require('./markdown/translate')
const headerPlugin = require('./markdown/header')
const createSidebar = require('./markdown/createSidebar')
const { simplifySlugText } = require('./utils')
const tabs = ['/uniCloud/', '/plugin/', '/worktile/', '/tutorial/', '/collocation/', '/component/', '/api/', '/']
const config = {
// TODO use theme
title: 'uni-app官网',
head: [
['link', {
rel: 'shortcut icon',
type: 'image/x-icon',
href: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-a90b5f95-90ba-4d30-a6a7-cd4d057327db/d23e842c-58fc-4574-998d-17fdc7811cc3.png?v=1556263038788'
}]
],
locales: {
'/': {
lang: 'zh-CN',
}
},
themeConfig: {
titleLogo: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/1ae87107-2943-4ba6-be2b-390ca27c6260.png',
logo: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/5a7f902b-21a7-4822-884f-925219eacc4b.png',
// TODO use plugin/theme
sidebar: createSidebar(tabs),
// sidebarDepth: 2,
nextLinks: false,
prevLinks: false,
// TODO use theme
repo: 'dcloudio/uni-app',
docsRepo: 'https://gitee.com/dcloud/unidocs-zh',
docsBranch: 'vuepress',
docsDir: 'docs',
editLinks: true,
editLinkText: '帮助我们改善此页面!',
// smoothScroll: true,
algolia: {
apiKey: '2fdcc4e76c8e260671ad70065e60b2e7',
indexName: 'zh-uniapp',
appId: 'PQIR5NL8CZ',
searchParameters: { hitsPerPage: 50 }
}
},
markdown: {
slugify(str) {
if (typeof str !== 'string') return ''
let slug = str
if (slug.includes('@')) {
let array = slug.split('@')
slug = array.length > 1 ? array[array.length - 1] : str
} else {
slug = simplifySlugText(slug.toLowerCase()).trim()
}
return slugify(slug)
},
extractHeaders: ['h1', 'h2', 'h3', 'h4'],
chainMarkdown(config) {
config
.plugin('translate')
.use(translatePlugin)
.end()
.plugin('convert-header')
.use(headerPlugin)
.end()
.plugin('normallize-link')
.use(require('./markdown/normallizeLink'))
}
}
}
module.exports = config
\ No newline at end of file
function createMarkdownArray(contents = [], childrenName = 'children') {
const markdownArray = []
let itemCatch = {}
for (let index = 0; index < contents.length; index++) {
const item = contents[index];
if (itemCatch.parent) {
if (item.level === itemCatch.level) {
const child = {
...item,
parent: itemCatch.parent
};
itemCatch.parent[childrenName].push(child)
delete itemCatch.parent
itemCatch = child
continue
} else if (item.level > itemCatch.level) {
const child = {
...item,
parent: itemCatch
};
(itemCatch[childrenName] || (itemCatch[childrenName] = [])).push(child)
itemCatch = child
} else {
const parent = itemCatch.parent
delete itemCatch.parent
itemCatch = parent
index--
continue
}
} else {
if (typeof itemCatch.level === 'undefined' || item.level === itemCatch.level) {
itemCatch = item
markdownArray.push(itemCatch)
} else {
const child = {
...item,
parent: itemCatch
};
(itemCatch[childrenName] || (itemCatch[childrenName] = [])).push(child)
itemCatch = child
continue
}
}
}
function removeParent(childs = []) {
childs.forEach(child => {
if (child.parent) delete child.parent
if (child[childrenName]) removeParent(child[childrenName])
})
}
// 移除最后一项 parent 节点,防止循环引用报错
removeParent(markdownArray[markdownArray.length - 1][childrenName])
return markdownArray
}
module.exports = createMarkdownArray
\ No newline at end of file
const fs = require('fs')
const path = require('path')
const MarkdownIt = require('markdown-it');
const createMarkdownArray = require('./createMarkdownArray')
const { isExternal } = require('../utils')
function parseBar(file, options) {
const textName = options.text || 'text'
const linkName = options.link || 'link'
const contents = []
new MarkdownIt()
.parse(fs.readFileSync(file, { encoding: 'utf-8' }))
.forEach(token => {
if (token.type === 'inline') {
let [_, text, link] = token.content.match(/\[(.+?)\]\((.+?)\)/) || token.content.match(/(.+)/)
link = link && (
isExternal(link)
? link
: path.join('/', link.replace(/\.md\b/, '')
.replace(/\bREADME\b/, '')
.replace(/\/index/, '/')
.replace(/\?id=/, '#'))
.replace(/\\/g, '/')
)
contents.push({
level: token.level,
[textName]: text,
[linkName]: link
})
}
})
return createMarkdownArray(contents, options.children)
}
module.exports = function (tabs = []) {
const sidebar = {}
tabs.forEach(tab => {
sidebar[tab] = parseBar(path.join(__dirname, '../../', tab, '_sidebar.md'), {
text: 'title',
link: 'path'
})
})
return tabs.length ? sidebar : false
}
\ No newline at end of file
function parseHeader(tokens) {
tokens.forEach((t, i) => {
if (t.type === 'heading_open' && /h\d/.test(t.tag)) {
const token = tokens[i + 1]
const title = token.content
const res = title.match(/\s*(.+?)@(.+?)\s*$/)
if (res) {
token.content = res[1]
for (let i = 0, array = token.children, l = array.length; i < l; i++) {
const token = array[l - 1 - i]
if (token.type === 'text') {
const title = token.content
const res = title.match(/(.*)@.+/)
if (res) {
token.content = res[1]
break
}
}
}
}
}
})
return tokens
}
module.exports = md => {
md.parse = (function (mdParse) {
return function (src, ...array) {
return parseHeader(mdParse.bind(this)(src, ...array))
}
})(md.parse)
}
const fs = require('fs')
const folderNames = []
fs.readdirSync('docs').forEach(item => {
fs.lstatSync(`docs/${item}`).isDirectory() && folderNames.push(item)
})
function isExternal(path) {
return /^[a-z]+:/i.test(path)
}
function normalizeLink(url) {
if (!url.startsWith('/') && folderNames.some(item => url.split('/')[0] === item)) {
return '/' + url
}
return url
}
module.exports = function (md) {
md.normalizeLink = (function (oldNormalizeLink) {
return function (url) {
url = isExternal(url)
? url
: normalizeLink(url)
.replace(/\.md\b/, '')
.replace(/\bREADME\b/, '')
.replace(/\/index/, '/')
.replace(/\?id=/, '#')
.replace(/\\/g, '/')
return oldNormalizeLink.bind(this)(url)
}
})(md.normalizeLink)
}
\ No newline at end of file
module.exports = md => {
md.parse = (function (mdParse) {
return function (src, ...array) {
return mdParse.bind(this)(src, ...array)
}
})(md.parse)
md.render = (function (mdRender) {
return function (src, ...array) {
return mdRender.bind(this)(src, ...array)
}
})(md.render)
}
<template>
<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';
export default {
name: 'AlgoliaSearchBox',
watch: {},
mounted() {},
methods: {
openSearch(){
this.$parent.$refs.dcloudSearchPage.onSearchOpen()
}
},
};
</script>
<style lang="stylus">
.DocSearch
--docsearch-primary-color $accentColor
--docsearch-highlight-color var(--docsearch-primary-color)
--docsearch-searchbox-shadow inset 0 0 0 2px var(--docsearch-primary-color)
#docsearch
display flex
flex-direction column
justify-content center
#docsearch span
@media (min-width: $MQMobile)
&
display flex
@media (max-width: $MQMobile)
:root
--docsearch-spacing 10px
--docsearch-footer-height 40px
.DocSearch-Button-Keys,.DocSearch-Button-Key,.DocSearch-Button-KeySeparator,.DocSearch-Button-Placeholder
display none !important
.DocSearch-Search-Icon
vertical-align middle
.DocSearch-Dropdown
height 100%
.DocSearch-Container
height 100vh
height -webkit-fill-available
position absolute
.DocSearch-Footer
border-radius 0
bottom 0
position absolute
.DocSearch-Hit-content-wrapper
display flex
position relative
width 80%
.DocSearch-Modal
border-radius 0
box-shadow none
height 100vh
height -webkit-fill-available
margin 0
max-width 100%
width 100%
.DocSearch-Cancel
-webkit-appearance none
-moz-appearance none
appearance none
background none
border 0
color var(--docsearch-highlight-color)
cursor pointer
display inline-block
flex none
font inherit
font-size 1em
font-weight 500
margin-left var(--docsearch-spacing)
outline none
overflow hidden
padding 0
-webkit-user-select none
-moz-user-select none
-ms-user-select none
user-select none
white-space nowrap
.DocSearch-Commands,.DocSearch-Hit-Tree
display none
</style>
<template>
<li :class="li_class">
<a :href="item.url">
<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 {};
},
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">
<span v-if="tag" class="DocSearch-Hit-source_tag">
{{ tag }}
</span>
{{ title }}
</div>
<ul id="docsearch-list">
<template v-for="(item, index) in results">
<Result
:key="[title, item.objectID].join(':')"
:item="item"
:index="index"
@click.native="event => onSelect({ item, event })"
/>
</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: [],
},
onSelect: {
type: Function,
default: () => {},
},
},
computed: {
tag() {
return this.results[0].tag !== 'uniCloud' ? this.results[0].tag : '';
},
},
};
</script>
<style lang="stylus">
#docsearch-list{
border-radius: 5px;
padding: 0;
border: 1px solid #dfe2e5;
overflow: hidden;
}
.DocSearch-Hits mark {
background: none;
color: $accentColor;
}
.DocSearch-Hit-source {
background-color $search-container-color;
color: $accentColor;
font-size 1em;
padding 15px 4px 15px
}
.DocSearch-Hit-source_tag {
background-color: #f0f0f0;
font-size: 12px;
padding: 2px 4px;
color: #999;
border-radius: 3px;
margin-right: 5px;
font-weight: normal;
}
</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
@import './styles/ext.styl'
@import './styles/ask.styl'
#search-container
position relative
overflow auto
position fixed
width 100%
height 100%
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
padding-top 20px
font-size 20px
.uni-loading
width 27px
height 27px
.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
.algolia-logo
display flex
justify-content center
padding 10px 0 20px
.search-more
display block
text-align center
padding 10px 0
color inherit
cursor pointer
&:hover
color $accentColor
@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
\ 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
v-if="item.link"
:key="item.text"
:item="{
...item,
link: item.link + searchValue,
}"
/>
<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 v-if="showLoading" class="uni-loading"></span>
<span v-else>{{ resultText }}</span>
</div>
<div class="search-result">
<div class="result-wrap">
<template v-if="isAlgolia">
<template v-for="item in resultList">
<Results
:key="item.sourceId"
:title="item.title"
:results="item.items"
:onSelect="item.onSelect"
/>
</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" class="algolia-logo">
<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"
/>
<a v-if="showMoreAsk" class="search-more" @click="moreAskResult">
<span v-if="showServerLoading" class="uni-loading"></span>
<span v-else>{{ hasNoMoreServerResult ? '没有更多了' : '更多...' }}</span>
</a>
</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 './utils/searchClient';
import { postExt, postAsk } from './utils/postDcloudServer';
import { forbidScroll, debounce } from '../../util';
import { removeHighlightTags, isEditingContent } from './utils/searchUtils';
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 },
data() {
return {
openSearch: false,
placeholder: '搜索内容',
snippetLength: 30,
searchValue: '',
category: Object.freeze([
{
text: 'uni-app',
type: 'algolia',
},
{
text: 'uniCloud',
type: 'algolia',
},
{
text: '问答社区',
tag: 'ask',
type: 'server',
},
{
text: '插件市场',
tag: 'ext',
type: 'server',
},
{
text: '原生开发文档',
type: 'link',
link: 'https://nativesupport.dcloud.net.cn/?s=',
},
{
text: 'HBuilderX 文档',
type: 'link',
link: 'https://hx.dcloud.net.cn/?s=',
},
]),
categoryIndex: 0,
resultList: [],
noResult: false,
serverHtml: '',
showLoading: false,
showServerLoading: false,
hasNoMoreServerResult: false,
searchPage: 0, // 跳转页数
curHits: 0, // 当前搜索结果总条数
totalPage: 0, // 搜索结果总共页数
curPage: 1, // 当前页
pageSize: 0, // 每页条数
};
},
computed: {
currentCategory() {
return this.category[this.categoryIndex];
},
isAlgolia() {
return this.currentCategory.type === 'algolia';
},
isAsk() {
return this.currentCategory.tag === 'ask';
},
showPagination() {
return !!(this.resultList.length && this.totalPage > 1 && this.isAlgolia);
},
showMoreAsk() {
return this.isAsk && this.serverHtml;
},
resultText() {
return this.noResult
? `没有找到${this.currentCategory.text}相关内容`
: !this.isAsk
? `${this.curHits}个相关结果`
: `以下为${this.currentCategory.text}相关内容`;
},
},
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();
this.initResultWrapHeight();
});
} else {
this.cancel();
forbidScroll(false);
document.body.removeChild(this.$el);
}
});
},
searchValue: debounce(function () {
this.resetSearchPage();
this.search();
}, 300),
},
methods: {
initResultWrapHeight() {
const pageHeight = this.$el.clientHeight;
const searchNavbarHeight = document.querySelector('.search-navbar').clientHeight;
const resultNumberHeight = (
document.querySelector('.result-number') || { clientHeight: 47 }
).clientHeight;
const algoliaLogoHeight = (document.querySelector('.algolia-logo') || { clientHeight: 49 })
.clientHeight;
const searchPagination = 36;
document.querySelector('.result-wrap').style.minHeight =
pageHeight -
searchNavbarHeight -
resultNumberHeight -
algoliaLogoHeight -
searchPagination -
20 +
'px';
},
resetSearchPage() {
this.searchPage = 0;
},
research(curPage) {
this.searchPage = curPage - 1;
this.search();
},
search() {
if (!this.searchValue || !this.searchValue.trim().length) return;
const { type } = this.currentCategory;
switch (type) {
case 'algolia':
this.showLoading = true;
this.searchByAlgolia()
.then(({ hitsPerPage, nbHits, nbPages, page, hits }) => {
this.resultList = hits.map(item => {
const items = item.getItems();
return {
...item,
title: removeHighlightTags(items[0]),
items,
};
});
this.noResult = !this.resultList.length;
this.curHits = nbHits;
this.pageSize = hitsPerPage;
this.totalPage = nbPages;
this.curPage = page + 1;
})
.finally(() => (this.showLoading = false));
break;
case 'server':
this.showLoading = true;
this.searchByServer().finally(() => (this.showLoading = false));
break;
}
},
searchByAlgolia() {
const { searchParameters = {} } = this.options;
return searchClient(
Object.assign({}, this.options, {
query: this.searchValue || '',
page: this.searchPage,
snippetLength: this.snippetLength,
searchParameters: {
...searchParameters,
facetFilters: [`lang:${this.$lang}`].concat(searchParameters.facetFilters || [], [
`category:${this.currentCategory.text}`,
]),
},
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),
};
}),
onClose: this.onSearchClose,
})
);
},
searchByServer(append = false) {
const { tag } = this.currentCategory;
const query = this.searchValue || '';
switch (tag) {
case 'ext':
return postExt(query).then(({ html, hits }) => {
this.serverHtml = html;
this.curHits = hits;
this.noResult = !hits;
});
case 'ask':
append && (this.showServerLoading = true);
this.searchPage === 0 && (this.searchPage = 1);
return postAsk(query, this.searchPage)
.then(res => {
if (res) {
const { html = '', hits } = res;
if (append) {
this.serverHtml += html;
} else {
this.hasNoMoreServerResult = false;
this.serverHtml = html;
}
this.noResult = !this.serverHtml.length;
} else {
if (append) {
this.hasNoMoreServerResult = true;
} else {
this.serverHtml = '';
this.noResult = true;
}
}
})
.finally(() => (this.showServerLoading = false));
}
},
moreAskResult() {
if (this.hasNoMoreServerResult) return;
this.searchPage === 0 ? (this.searchPage = 2) : this.searchPage++;
this.searchByServer(true);
},
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;
}
if (this.$refs.pageContainer) {
this.$refs.pageContainer.style.maxHeight = document.documentElement.clientHeight;
this.$refs.pageContainer.style.maxWidth = document.documentElement.clientWidth;
}
},
switchCategory(index) {
this.categoryIndex = index;
this.research(1);
},
cancel() {
this.resultList.length = 0;
this.searchValue = '';
this.curHits = 0;
this.totalPage = 0;
this.serverHtml = '';
this.noResult = false;
},
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>
#search-container
.aw-item, .plugin-li
box-sizing border-box
$padding-n = 25px
padding $padding-n $padding-n ($padding-n - 10px) $padding-n
@media (max-width $MQMobile)
&
padding: $padding-n - 10px $padding-n - 10px 5px $padding-n - 10px
&:not(:last-child)
border-bottom 1px solid #eee
&:first-child
margin-top 0 !important
.aw-item
a
text-decoration none
color inherit
font-weight 400
p
margin 0 0 10px
.tip-recommend
background-color #22ac38
color #ffffff
padding 2px 5px
border-radius 3px
margin-right 10px
font-size 12px
.aw-title a
text-decoration underline
font-size 16px
.aw-hide-text
font-size 12px
color #828288
.aw-search-result-tags
background-color #ffffff
color #ef5656
margin-right 10px
.aw-search-body
font-size 14px
color #666
word-break: break-all;
em
font-weight bold
font-style normal
color $accentColor
.plugin-li
color rgba(0, 0, 0, 0.6)
width 100%
text-align -webkit-match-parent
font-size 14px
.pull-right
float right !important
.col-lg-9
width 70%
.col-lg-2
width 16.66666667%
.col-lg-6
width 50%
float left
.col-md-6, .col-lg-6, .col-xs-12, .col-sm-12
position relative
min-height 1px
padding-left 15px
padding-right 15px
a
color inherit
:before, :after
box-sizing border-box
.row
margin-right -15px
margin-left -15px
&:before, &:after
content ' '
display table
&:after
clear both
.card
margin-bottom 15px
border-radius 10px
background-color #fff
&:last-child
margin-bottom 0
.preview-img
display inline-block
max-height 192px
padding-right 0
float left
overflow-y hidden
img
width 100%
height auto
vertical-align middle
border 0
.plugin-info
padding-left 30px
padding-right 0
float left
.row
margin-bottom 8px
&:last-child
margin-bottom 0
.extend-list
margin 0
position relative
line-height 24px
color #999
transition all 0.3s
.extend-list-header .extend-title a
color #595a78
font-size 16px
.extend-list-desc
color #424249
font-size 14px
.badge
padding 2px 6px
margin-left 5px
display inline-block
min-width 10px
padding 3px 7px
font-size 12px
font-weight 700
color #fff
line-height 1
vertical-align baseline
white-space nowrap
text-align center
background-color #999
border-radius 10px
.bg-green, .bg-green:hover
color #639069
a.&:focus, a.&:hover
color #fff
text-decoration none
cursor pointer
h2
margin-top 0
padding-bottom 0
font-size 100%
line-height 20px
color #333
border none
.ext-slg
padding 0
margin 0 auto
width 14%
float right
text-align center
.rating
margin-top 10px
.star-rating
unicode-bidi bidi-override
color #96969b
font-size 0
height 25px
position relative
display inline-block
padding 0
margin-left 0
float left
span
padding 1px
font-size 16px
.star-rating-top
color #fde16d
padding 0
position absolute
z-index 1
display inline-block
top 4px
left 4px
overflow hidden
white-space nowrap
float left
span
width 20px
height 16px
background url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAASCAYAAAC5DOVpAAABDUlEQVQ4ja3SsS/DQRjG8c81YrLYxCz8pLHUYhCtzf9gtIilo1VM/gSmisR/YCCRSMTIyhEzo7nR9CytVPn112qf5Ib3fZ/73nO5o0ApaqQopahR5C0C1Tqg7qoN8pcKeAcF9XCwTopqX7s6KF3IAU3hBut/jO+wGTKtX7AUzWALS1jEApYxm5cAH3jCK17wjKuQonusDtg4rB5CipqYngCsWUJ9AiCol0LmGLtojwHaC5mT79dM0TbOFP+9XrWxEzKnejeGzLnRr7zfBf2AdfQ2Iuy9t+iHrYwI++EfF1b+D+wxpz8w2VxffYlKyJRRwUXffD7nEFJ0mKLPFN2maCPHs5ai6xS1UnTUO/sCG35T7tAgzwcAAAAASUVORK5CYII=') no-repeat
background-size 16px
.star-rating-bottom
padding 4px
display inline-block
z-index 0
float left
span
width 20px
height 16px
background url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAASCAYAAAC5DOVpAAABBElEQVQ4ja3Ur04DQRDH8U8vSAyOoFkIAUxRqFaC4BUIdQRTiW1ST4KCKmp4AwQIFBZSB2GDBskLQIPgStojd9d/Y3ZnfjPfzGYmW4kxKrErHKGLRlYMIfzdkxJQPQVJz3pRchmsVeKPDaujlonVFHSXB1tAO0drp/o/q8QYF7GHdaxhFRtYyusAn3jBGyJecVeJMT5ip6BwXHtKsD0HEGwlaM4J1kxwiWP0ZwCdhBA6g2l2cDgFsI9GCOGC0dW4NvmTT0MI3YGT3bP3CWEfw04WNulkR/JnhW1OA3vOiRd2tpzxb1FNO6jiJqOvFMHO8YUHvz/EPnqp1sMBdnGPb5wNF/8A+HAvGx6fm+sAAAAASUVORK5CYII=') no-repeat
background-size 16px
.glyphicon
position relative
top 1px
display inline-block
font-family 'Glyphicons Halflings'
font-style normal
font-weight 400
line-height 1
-webkit-font-smoothing antialiased
-moz-osx-font-smoothing grayscale
.extend-list-tag
.badge.bg-orange
color #ff7c00
background rgba(255, 194, 0, 0.28) !important
.badge.bg-green
color #639069
background-color #eff9f0 !important
.extend-list-more
font-size 13px
color #828288
line-height 40px
.categorys
width 45% !important
a
color #22ac38
.col-lg-4
float left
.extend-list-user .avatar
width 30px
height 30px
border-radius 100%
margin-right 10px
margin-left 10px
\ No newline at end of file
#search-container
.markdown-section
margin-top 20px
background-color #fff
.matching-post
$padding-n = 25px
padding $padding-n $padding-n ($padding-n - 15px)$padding-n
@media (max-width $MQMobile)
&
padding: $padding-n - 10px $padding-n - 10px 0px $padding-n - 10px
&: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
font-weight normal
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 12px
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 16px
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
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"
},
askHtml: `<div
class="aw-item active" >
<p class="aw-title">
<span class="tip-recommend">官方</span>
<a href="//ask.dcloud.net.cn/article/676" target="_blank"> 手机端监听<em>短信</em>验证码并自动提交表单 </a>
</p>
<p class="aw-search-body">
鉴定<em>短信</em>验证码仅能在App端实现,其他端无法使用。但在App端,更为合理的方式其实是使用一键登录。即无需<em>短信</em>验证码,一键登录获取真实的手机号。一键登陆的体验比<em>短信</em>验证码好很多,不需等待验证码、输入验证码,并且一键登陆的费用比<em>短信</em>便宜不少。所以*强烈推荐改用一键登陆*,uni一键登陆的文档另见:... </p>
<p class="aw-hide-text aw-text-color-666">
分类:
<a class="aw-search-result-tags"> 文章 </a>
77 个回复 •
32933 次查看 </p>
</div>
<div
class="aw-item active" >
<p class="aw-title">
<span class="tip-recommend">官方</span>
<a href="//ask.dcloud.net.cn/article/37534" target="_blank"> 发送<em>短信</em>教程(验证码、<em>短信</em>通知) </a>
</p>
<p class="aw-search-body">
添加模板完成后,如模板审核通过,则根据[https://uniapp.dcloud.io/uniCloud/send-<em>sms</em>](https://uniapp.dcloud.io/uniCloud/send-<em>sms</em>)进行<em>短信</em>接入。[attach]61670[/attach] 充值 <em>短信</em>验证码为预付费业务,使用<em>短信</em>验证码服务之前,需要先进行充值。点击页面上的“充值”按钮,可以选择预设金额进行充值,也可以选择自定义... </p>
<p class="aw-hide-text aw-text-color-666">
分类:
<a class="aw-search-result-tags"> 文章 </a>
60 个回复 •
16940 次查看 </p>
</div>
<div
class="aw-item active" >
<p class="aw-title">
<span class="tip-recommend">官方</span>
<a href="//ask.dcloud.net.cn/article/37746" target="_blank"> 公告:<em>短信</em>模板报备通知 </a>
</p>
<p class="aw-search-body">
由于近期有个别开发者利用<em>短信</em>服务发送违法信息,导致【uniID】、【uni验证】等<em>短信</em>服务模板被运营商停用。为了保证其他开发者可以正常使用,即日起,开发者使用<em>短信</em>服务需要进行<em>短信</em>模板...参考文档[https://uniapp.dcloud.net.cn/uniCloud/send-<em>sms</em>](https://uniapp.dcloud.net.cn/uniCloud/send-<em>sms</em>)更新发送<em>短信</em>相关代码。 </p>
<p class="aw-hide-text aw-text-color-666">
分类:
<a class="aw-search-result-tags"> 文章 </a>
43 个回复 •
3276 次查看 </p>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 plugin-li" data="4542">
<div class="row extend-list card has-preview-img">
<div class="col-sm-3 col-md-3 col-lg-3 preview-img should-pop" style="width: 20%;" data-toggle="popover" data-src="//img-cdn-aliyun.dcloud.net.cn/stream/plugin_screens/3c30aa60-8d63-11eb-9913-cd96a30ab764_0.jpg?image_process=quality,q_70&amp;v=1641979438" data-original-title="" title="">
<a href="https://ext.dcloud.net.cn/plugin?id=4542" target="_blank">
<img src="//img-cdn-aliyun.dcloud.net.cn/stream/plugin_screens/3c30aa60-8d63-11eb-9913-cd96a30ab764_0.jpg?image_process=quality,q_70&amp;v=1641979438">
</a>
</div>
<div class="col-xs-12 col-sm-9 col-md-9 col-lg-9 plugin-info">
<div class="row extend-list-header">
<div class="col-xs-12 col-sm-12 col-md-6 col-lg-6">
<h2 class="extend-title elip">
<a href="https://ext.dcloud.net.cn/plugin?id=4542" target="_blank"> <em>升级中心</em> uni-upgrade-center-App </a>
</h2>
</div>
<div class="collection col-xs-6 col-sm-6 col-md-2 col-lg-2 pull-right ext-slg">
<a href="https://ext.dcloud.net.cn/plugin?id=4542" target="_blank" style="color: #ef5656;">
<img src="//img-cdn-aliyun.dcloud.net.cn/dev/img/ext/collection-small.png">&nbsp;收藏&nbsp;<span class="collection-list-total-4542">385</span>
</a>
</div>
<div class="support col-xs-6 col-sm-6 col-md-2 col-lg-2 pull-right ext-slg">
<a href="https://ext.dcloud.net.cn/plugin?id=4542" target="_blank" style="color: #ef5656;">
<img src="//img-cdn-aliyun.dcloud.net.cn/dev/img/ext/heart.png">&nbsp;赞赏&nbsp;3 </a>
</div>
<div class="download col-xs-6 col-sm-6 col-md-2 col-lg-2 pull-right ext-slg">
<a href="https://ext.dcloud.net.cn/plugin?id=4542" target="_blank" style="color: #4e92df;">
<img src="//img-cdn-aliyun.dcloud.net.cn/dev/img/ext/download.png">&nbsp;下载&nbsp;11539 </a>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<a href="https://ext.dcloud.net.cn/plugin?id=4542" target="_blank">
<span class="extend-list-desc">
uni<em>升级中心</em>-客户端检查更新 </span>
</a>
</div>
</div>
<div class="row rating" title="评分: 4.8 (129人评分)">
<div class="col-xs-12">
<div class="star-rating">
<div class="star-rating-top" style="width:95%">
<span class="glyphicon"></span>
<span class="glyphicon"></span>
<span class="glyphicon"></span>
<span class="glyphicon"></span>
<span class="glyphicon"></span>
</div>
<div class="star-rating-bottom">
<span class="glyphicon"></span>
<span class="glyphicon"></span>
<span class="glyphicon"></span>
<span class="glyphicon"></span>
<span class="glyphicon"></span>
</div>
</div>
<span class="star-rating-text">(129)</span>
</div>
</div>
<div class="row extend-list-tag">
<div class="col-xs-12">
<a class="badge bg-orange" href="javascript:;">uni_modules</a>
<a class="badge bg-green" href="javascript:;">uniCloud</a>
<a class="badge bg-green" href="javascript:;">update</a>
<a class="badge bg-green" href="javascript:;">升级</a>
<a class="badge bg-green" href="javascript:;">wgt</a>
</div>
</div>
<div class="row extend-list-more">
<div class="categorys col-xs-12 col-sm-6 col-md-4 col-lg-4" style="width:60%">
分类:<a href="javascript:;">uniCloud</a> /
<a href="javascript:;">云端一体页面模板</a>
</div>
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4" style="width:30%">
更新日期:2022-01-12</div>
<div class="extend-list-user col-md-4 col-lg-4" style="width: 10%">
<a href="https://ext.dcloud.net.cn/publisher?id=586192">
<img class="avatar pull-right" src="https://img-cdn-tc.dcloud.net.cn/uploads/avatar/001/67/43/81_avatar_max.jpg" alt="DCloud前端团队">
<span class="pull-right"></span>
</a>
</div>
</div>
</div>
<div class="plugin-action" style="display: none;">
<div class="plugin-like-btn " onclick="collection(this, 4542)">收藏</div>
</div>
</div>
</div>
`
}
\ No newline at end of file
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 不可为空')
const xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
resolve(this.response)
}
}
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, page = 1) {
const base = isProduction ? '//ask.dcloud.net.cn' : '/ask'
let askHtml = '';
if (!isMock) {
askHtml = await ajax(base + `/search/ajax/search_result/search_type-all__q-${query}__page-${page}`)
if (!askHtml) {
return;
}
} else {
askHtml = mock.askHtml
}
return {
html: askHtml,
hits: 0
}
}
function _renderExt(ext, keyword) {
return `<div class="matching-post">
<a href="${ext.url}" target="_blank">
<div class="post-wrapper">
<h2>
<p class="aw-text">
<span class="post-tag">插件</span>
</p>
${_handleHTMLString(ext.name, keyword)}
</h2>
</div>
<p>${ext.total_download}次下载</p>
<p>${_handleHTMLString(ext.description, keyword)}</p>
</a>
</div>`
}
function _renderPost(post, value) {
let html = '';
let commentText = '';
let 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">
<h2>
<p class="aw-text">
<span class="post-tag">${tagName}</span>
</p>
${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) {
let keywordReg = new RegExp(
keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'),
'gi'
);
let tagStartReg = new RegExp(
'&lt;span style=\'font-weight:bold;color:red\'&gt;',
'g'
);
let 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 './searchUtils'
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 = () => { }, onClose = () => { }, ...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',
'url_without_anchor',
'category',
'tag'
],
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
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
<template>
<div ref="container" id="footNavBox">
<div class="footNav">
<div id="footNavClassify">
<footNavItem :list="footNavList" />
</div>
<div id="aboutusBox">
<footNavItem :list="aboutusList" />
</div>
</div>
<div class="hbLogo"></div>
<div class="companyBox">
<span class="companyInfo">DCloud 即数字天堂(北京)网络技术有限公司是</span>
<div style="display: inline; margin-left: 5px" class="companyInfo">
<a href="//www.w3.org/" target="_blank" class="w3c">W3C</a>
成员及
<a href="//www.html5plus.org/" target="_blank" class="html5">HTML5中国产业联盟</a>
发起单位
</div>
</div>
<div class="beianBox">
<a
id="domain"
class="beian"
href="https://beian.miit.gov.cn/#/Integrated/index"
target="_blank"
>
{{ domain }}
</a>
<div class="domainImgBox">
<img
class="domainImg"
src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/769929a3-65eb-4d11-815d-84f88197a152.png"
/>
<a
class="beian"
href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010802035340"
target="_blank"
>
京公网安备:11010802035340号
</a>
</div>
<span class="anbaoInfo">国家信息安全等级保护三级,证书编号:11010813802-20001</span>
</div>
</div>
</template>
<script>
export default {
components: {
footNavItem: {
functional: true,
props: {
list: {
type: Array,
default: () => [],
},
},
render: (h, { props }) => {
return props.list.map((footNavListItem, _index) =>
h('div', { staticClass: 'footNavItem', key: footNavListItem.title || _index }, [
h('div', { staticClass: 'navItemTitle' }, footNavListItem.title),
h('div', { staticClass: 'navLine' }),
h(
'div',
{ staticClass: 'navItemDetailBox' },
footNavListItem.content.map((item, index) =>
h(
'a',
{
staticClass: 'navItemDetail',
key: item.url || index,
attrs: {
target: '_blank',
href: item.url,
},
},
item.subTitle
)
)
),
])
);
},
},
},
data: () => ({
footNavList: [
{
title: '开发产品',
content: [
{
subTitle: 'HBuilderX',
url: 'https://www.dcloud.io/hbuilderx.html',
},
{
subTitle: 'uni-app',
url: 'https://uniapp.dcloud.net.cn/',
},
{
subTitle: 'uniCloud',
url: 'https://uniapp.dcloud.net.cn/uniCloud/README',
},
{
subTitle: 'uniMPsdk',
url: 'https://nativesupport.dcloud.net.cn/',
},
{
subTitle: '5+Runtime',
url: 'https://www.dcloud.io/runtime.html',
},
{
subTitle: 'wap2app',
url: 'https://www.dcloud.io/wap2app.html?platform=wap2app',
},
{
subTitle: 'MUI',
url: 'https://www.dcloud.io/mui.html',
},
{
subTitle: 'uni-id',
url: 'https://uniapp.dcloud.net.cn/uniCloud/uni-id',
},
{
subTitle: 'uniPay',
url: 'https://uniapp.dcloud.net.cn/uniCloud/unipay',
},
{
subTitle: 'uniPush',
url: 'https://uniapp.dcloud.net.cn/unipush',
},
{
subTitle: 'uni-verify',
url: 'https://uniapp.dcloud.io/univerify',
},
{
subTitle: 'sms',
url: 'https://uniapp.dcloud.net.cn/uniCloud/send-sms',
},
{
subTitle: 'uni-starter',
url: 'https://ext.dcloud.net.cn/plugin?id=5057',
},
{
subTitle: 'uni-admin',
url: 'https://uniapp.dcloud.net.cn/uniCloud/admin',
},
{
subTitle: 'uni-upgrade-center',
url: 'https://uniapp.dcloud.io/uniCloud/upgrade-center',
},
],
},
],
aboutusList: [
{
title: '运营产品',
content: [
{
subTitle: 'uni-AD',
url: 'https://uniad.dcloud.net.cn/login',
},
{
subTitle: 'uni统计',
url: 'https://tongji.dcloud.net.cn/',
},
{
subTitle: 'uni发行',
url: 'https://www.dcloud.io/dportal.html',
},
{
subTitle: '',
url: '',
},
{
subTitle: '',
url: '',
},
{
subTitle: '',
url: '',
},
],
},
/* {
'title': '',
'content': []
}, */
{
title: '开发者服务',
content: [
{
subTitle: '问答社区',
url: 'https://ask.dcloud.net.cn/explore/',
},
{
subTitle: '开发者后台',
url: 'https://dev.dcloud.net.cn/',
},
],
},
{
title: '技术文档',
content: [
{
subTitle: 'uni-app文档',
url: 'https://uniapp.dcloud.io/',
},
{
subTitle: 'uniCloud文档',
url: 'https://uniapp.dcloud.io/uniCloud/README',
},
{
subTitle: '原生开发者支持文档',
url: 'https://nativesupport.dcloud.net.cn/',
},
{
subTitle: 'HBuilder文档',
url: 'https://hx.dcloud.net.cn/',
},
],
},
{
title: '生态服务',
content: [
{
subTitle: '插件市场',
url: 'https://ext.dcloud.net.cn/',
},
{
subTitle: 'OAuth用户开放平台',
url: 'https://open.dcloud.net.cn/pages/login/login',
},
],
},
{
title: '关于我们',
content: [
{
subTitle: 'DCloud官网',
url: 'https://dcloud.io/',
},
{
subTitle: '案例',
url: 'https://uniapp.dcloud.io/case',
},
{
subTitle: '需求墙',
url: 'https://dev.dcloud.net.cn/wish/?channel=uniapp',
},
{
subTitle: '许可协议',
url: 'https://ask.dcloud.net.cn/article/35623',
},
{
subTitle: '加入我们',
url: 'https://www.dcloud.io/hr/',
},
{
subTitle: '赞助我们',
url: 'https://dev.dcloud.net.cn/sponsor/',
},
],
},
{
title: '联系我们',
content: [
{
subTitle: '商务合作:bd@dcloud.io',
url: 'mailto:bd@dcloud.io',
},
{
subTitle: '广告合作:uniad@dcloud.io',
url: 'mailto:uniad@dcloud.io',
},
],
},
],
domain: '',
}),
mounted() {
if (document.domain === 'uniapp.dcloud.net.cn') {
this.domain = '京ICP备12046007号-4';
} else {
this.domain = '蒙ICP备14002744号-1';
}
this.fixBottom();
},
methods: {
fixBottom() {
this.$nextTick(() => {
this.$refs.container.style.bottom = `0px`;
const bottom =
document.documentElement.clientHeight -
this.$refs.container.getBoundingClientRect().bottom;
if (bottom > 0) {
const preBottom = parseFloat(this.$refs.container.style.bottom);
this.$refs.container.style.position = 'relative';
this.$refs.container.style.bottom = `-${bottom}px`;
} else {
this.$refs.container.removeAttribute('style');
}
});
},
},
watch: {
$route() {
this.fixBottom();
},
},
};
</script>
<style lang="stylus" scoped>
@import '../styles/footer.styl'
</style>
<template>
<div
v-if="show"
class="main-navbar-link"
>
<DropdownLink
v-if="item.type === 'links'"
:item="item"
/>
<NavLink
v-else
:item="item"
/>
</div>
</template>
<script>
import DropdownLink from '@theme/components/DropdownLink.vue'
import NavLink from '@theme/components/NavLink.vue'
export default {
name: 'MainNavbarLink',
components: {
DropdownLink,
NavLink
},
props: {
item: {
type: Object,
default: () => ({})
}
},
computed: {
show() {
return this.item.type === 'link'
? this.item.link
: this.item.type === 'links'
? !!this.item.items.length
: false
}
}
}
</script>
<style lang="stylus" scope>
.main-navbar-link a
color inherit
@media (max-width: $MQMobile)
ul
list-style none
a
padding-top 0 !important
</style>
\ No newline at end of file
<template>
<RouterLink
v-if="isInternal"
class="nav-link"
:to="link"
:exact="exact"
@focusout.native="focusoutAction"
>
{{ item.text }}
</RouterLink>
<a
v-else
:href="link"
class="nav-link external"
:target="target"
:rel="rel"
@focusout="focusoutAction"
>
{{ item.text }}
<OutboundLink v-if="item.needOutbound !== false && isBlankTarget" />
</a>
</template>
<script>
import { isExternal, isMailto, isTel, ensureExt } from '../util'
export default {
name: 'NavLink',
inject: [ 'customNavBar' ],
props: {
item: {
required: true
}
},
computed: {
link () {
return ensureExt(this.item.link)
},
exact () {
if (this.$site.locales) {
return Object.keys(this.$site.locales).some(rootLink => rootLink === this.link)
}
return this.link === '/'
},
isNonHttpURI () {
return isMailto(this.link) || isTel(this.link)
},
isBlankTarget () {
return this.target === '_blank'
},
isInternal () {
return !isExternal(this.link) && !this.isBlankTarget
},
target () {
if (this.isNonHttpURI) {
return null
}
if (this.item.target) {
return this.item.target
}
return isExternal(this.link) ? '_blank' : ''
},
rel () {
if (this.isNonHttpURI) {
return null
}
if (this.item.rel === false) {
return null
}
if (this.item.rel) {
return this.item.rel
}
return this.isBlankTarget ? 'noopener noreferrer' : null
}
},
methods: {
focusoutAction () {
this.$emit('focusout')
}
}
}
</script>
<template>
<nav
v-if="(userLinks.length || repoLink) && showSubNavBar"
class="nav-links"
>
<!-- user links -->
<div
v-for="item in userLinks"
:key="item.link"
class="nav-item"
>
<DropdownLink
v-if="item.type === 'links'"
:item="item"
/>
<NavLink
v-else
:item="item"
/>
</div>
<!-- repo link -->
<!-- <a
v-if="repoLink"
:href="repoLink"
class="repo-link"
target="_blank"
rel="noopener noreferrer"
>
{{ repoLabel }}
<OutboundLink />
</a> -->
</nav>
</template>
<script>
import DropdownLink from '@theme/components/DropdownLink.vue'
import { resolveNavLinkItem } from '../util'
import NavLink from '@theme/components/NavLink.vue'
import navInject from '../mixin/navInject';
export default {
name: 'NavLinks',
mixins: [ navInject ],
components: {
NavLink,
DropdownLink
},
computed: {
userNav () {
return this.customNavBar[this.navConfig.userNavIndex].items || []
// return this.$themeLocaleConfig.nav || this.$site.themeConfig.nav || []
},
nav () {
const { locales } = this.$site
if (locales && Object.keys(locales).length > 1) {
const currentLink = this.$page.path
const routes = this.$router.options.routes
const themeLocales = this.$site.themeConfig.locales || {}
const languageDropdown = {
text: this.$themeLocaleConfig.selectText || 'Languages',
ariaLabel: this.$themeLocaleConfig.ariaLabel || 'Select language',
items: Object.keys(locales).map(path => {
const locale = locales[path]
const text = themeLocales[path] && themeLocales[path].label || locale.lang
let link
// Stay on the current page
if (locale.lang === this.$lang) {
link = currentLink
} else {
// Try to stay on the same page
link = currentLink.replace(this.$localeConfig.path, path)
// fallback to homepage
if (!routes.some(route => route.path === link)) {
link = path
}
}
return { text, link }
})
}
return [...this.userNav, languageDropdown]
}
return this.userNav
},
userLinks () {
return (this.nav || []).map(link => {
return Object.assign(resolveNavLinkItem(link), {
items: (link.items || []).map(resolveNavLinkItem)
})
})
},
repoLink () {
const { repo } = this.$site.themeConfig
if (repo) {
return /^https?:/.test(repo)
? repo
: `https://github.com/${repo}`
}
return null
},
repoLabel () {
if (!this.repoLink) return
if (this.$site.themeConfig.repoLabel) {
return this.$site.themeConfig.repoLabel
}
const repoHost = this.repoLink.match(/^https?:\/\/[^/]+/)[0]
const platforms = ['GitHub', 'GitLab', 'Bitbucket']
for (let i = 0; i < platforms.length; i++) {
const platform = platforms[i]
if (new RegExp(platform, 'i').test(repoHost)) {
return platform
}
}
return 'Source'
}
}
}
</script>
<style lang="stylus">
.nav-links
display inline-block
a
line-height 1.4rem
color inherit
&:hover, &.router-link-active
color $accentColor
.nav-item
position relative
display inline-block
margin-left 1.5rem
line-height 2rem
&:first-child
margin-left 0
.repo-link
margin-left 1.5rem
@media (max-width: $MQMobile)
.nav-links
.nav-item, .repo-link
margin-left 0
@media (min-width: $MQMobile)
.nav-item > .nav-link:not(.external)
display block
height 40px
line-height 40px
min-width 24px
padding 0 2vw
background-color #fff
border-radius 4px
transition background .3s
font-size 14px
/* .nav-links a
&:hover, &.router-link-active
color $textColor*/
.nav-item > a:not(.external)
&:hover
background-color #f0f0f0
&.router-link-active
color #fff
background-color $accentColor
</style>
<template>
<header class="navbar" :class="{ 'navbar-fixed': fixedNavbar }">
<div class="main-navbar">
<!-- <SidebarButton @toggle-sidebar="$emit('toggle-sidebar')" /> -->
<NavbarLogo />
<div class="main-navbar-links can-hide">
<template v-for="(item, index) in customNavBar">
<div :class="mainNavLinkClass(index)" :key="item.text">
<MainNavbarLink v-if="item.type" :item='item' />
<a v-else href="javascript:;" @click="changeUserNav(index)">{{item.text}}</a>
</div>
</template>
</div>
<div class="mobile-main-navbar">
<div class="mobile-links_mobile">
<a href="javascript:;" class="mobile-links__btn" @click="toggleMobilePanel">{{mainNavBarText}}</a>
</div>
<div class="mobile-links__panel" :class="{open: showMobilePanel}">
<template v-for="(item, index) in customNavBar">
<div :class="mainNavLinkClass(index)" :key="item.text">
<MainNavbarLink v-if="item.type" :item='item' @click.native="toggleMobilePanel"/>
<a v-else href="javascript:;" @click="changeUserNav(index),toggleMobilePanel()">{{item.text}}</a>
</div>
</template>
</div>
</div>
<div
class="links"
:style="linksWrapMaxWidth ? {
'max-width': linksWrapMaxWidth + 'px'
} : {}"
>
<a class="switch-version" href="javascript:void(0)" @click="switchVersion">回到旧版</a>
<DcloudSearchPage v-if="isAlgoliaSearch" ref="dcloudSearchPage" :options="algolia"/>
<AlgoliaSearchBox v-if="isAlgoliaSearch" />
<SearchBox v-else-if="$site.themeConfig.search !== false && $page.frontmatter.search !== false" />
</div>
</div>
<div class="sub-navbar">
<NavLinks class="can-hide" />
<div class="mobile-sub-navbar">
<div class="subnavbar__item" @click="$emit('toggle-sidebar')">
<a href="javascript:;">{{subNavBarText}}</a>
</div>
</div>
</div>
</header>
</template>
<script>
import AlgoliaSearchBox from './AlgoliaSearchBox'
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';
export default {
name: 'Navbar',
mixins: [ navInject ],
components: {
SidebarButton,
NavLinks,
MainNavbarLink,
SearchBox,
AlgoliaSearchBox,
NavbarLogo,
DcloudSearchPage
},
data () {
return {
linksWrapMaxWidth: null,
showMobilePanel: false,
fixedNavbar: false
}
},
computed: {
algolia () {
return this.$themeLocaleConfig.algolia || this.$site.themeConfig.algolia || {}
},
isAlgoliaSearch () {
return this.algolia && this.algolia.apiKey && this.algolia.indexName
}
},
mounted () {
const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
const NAVBAR_VERTICAL_PADDING = parseInt(css(this.$el, 'paddingLeft')) + parseInt(css(this.$el, 'paddingRight'))
const handleLinksWrapWidth = () => {
if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {
this.linksWrapMaxWidth = null
} else {
this.linksWrapMaxWidth = this.$el.offsetWidth - NAVBAR_VERTICAL_PADDING
- (this.$refs.siteName && this.$refs.siteName.offsetWidth || 0)
}
this.$nextTick(this.initNavBar)
}
handleLinksWrapWidth()
window.addEventListener('resize', handleLinksWrapWidth, false)
this.initNavBar()
},
methods: {
initNavBar () {
os.init()
this.sideBar = document.querySelector('.sidebar')
this.navbar = document.querySelector('.navbar')
this.mainNavBar = document.querySelector('.main-navbar')
this.subNavBar = document.querySelector('.sub-navbar')
this.pageContainer = document.querySelector('.page')
this.navbarHeight = this.navbar.clientHeight
this.subNavBarHeight = this.subNavBar.clientHeight
this.mainNavBarHeight = this.mainNavBar.clientHeight
this.removeWindowScroll()
if (os.pc) {
this.onWindowScroll()
window.addEventListener('scroll', this.onWindowScroll, false)
}
},
removeWindowScroll () {
window.removeEventListener('scroll', this.onWindowScroll)
this.fixedNavbar = false
this.sideBar && this.sideBar.removeAttribute('style')
this.navbar && this.navbar.removeAttribute('style')
this.pageContainer && this.pageContainer.removeAttribute('style')
},
onWindowScroll () {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
{
let sideTop = this.navbarHeight - scrollTop
sideTop <= this.subNavBarHeight && (sideTop = this.subNavBarHeight)
this.sideBar && (this.sideBar.style.top = `${sideTop + 1}px`)
}
if (scrollTop >= this.mainNavBarHeight) {
if (!this.fixedNavbar) {
this.fixedNavbar = true
this.navbar.style.top = `-${this.mainNavBarHeight}px`
this.$nextTick(() => {
this.pageContainer && (this.pageContainer.style.marginTop = `${this.navbarHeight}px`)
})
}
} else if (scrollTop < this.mainNavBarHeight) {
if (this.fixedNavbar) {
this.fixedNavbar = false
this.pageContainer && this.pageContainer.removeAttribute('style')
}
}
},
mainNavLinkClass (index) {
return ['main-navbar-item', this.navConfig.userNavIndex === index ? 'active' : '']
},
toggleMobilePanel () {
this.showMobilePanel = !this.showMobilePanel
forbidScroll(this.showMobilePanel)
},
switchVersion () {
document.cookie = encodeURIComponent('__old_version') + "=__old_version; path=/"
// document.cookie = encodeURIComponent('__new_version') + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/"
location.replace(location.origin + '?v=' + Date.now())
}
},
watch: {
'navConfig.userNavIndex' () {
this.$nextTick(()=>{
if(!os.pc) return
this.navbarHeight = this.navbar.clientHeight
this.subNavBarHeight = this.subNavBar.clientHeight
this.sideBar.style.top = `${this.navbarHeight + 1}px`
})
}
}
}
function css (el, property) {
// NOTE: Known bug, will return 'auto' if style value is 'auto'
const win = el.ownerDocument.defaultView
// null means not to return pseudo styles
return win.getComputedStyle(el, null)[property]
}
</script>
<style lang="stylus">
$navbar-vertical-padding = 0.7rem
$navbar-horizontal-padding = 1.5rem
@import '../styles/navbar'
.navbar
// padding $navbar-vertical-padding $navbar-horizontal-padding
line-height $navbar-main-navbar-height // $navbarHeight - 1.4rem
a, span, img
display inline-block
.title-logo
.logo
height $navbar-logo-height // $navbarHeight - 1.4rem
min-width $navbar-main-navbar-height // $navbarHeight - 1.4rem
margin-right 0.8rem
vertical-align top
.site-name
font-size 1.3rem
font-weight 600
color $textColor
position relative
.links
padding-left 1.5rem
box-sizing border-box
background-color white
white-space nowrap
font-size 0.9rem
position absolute
right $navbar-horizontal-padding
top 0 //$navbar-vertical-padding
display flex
.search-box
flex: 0 0 auto
vertical-align top
@media (max-width: $MQMobile)
.navbar
// padding-left 4rem
.can-hide
display none !important
.links
padding-left 0rem // 1.5rem
.site-name
width calc(100vw - 9.4rem)
overflow hidden
white-space nowrap
text-overflow ellipsis
</style>
<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>
<template>
<div class="search-box">
<input
ref="input"
aria-label="Search"
:value="query"
:class="{ focused: focused }"
:placeholder="placeholder"
class="custom-search"
autocomplete="off"
spellcheck="false"
@input="query = $event.target.value"
@focus="focused = true"
@blur="focused = false"
@keyup.enter="go(focusIndex)"
@keyup.up="onUp"
@keyup.down="onDown"
/>
<ul
v-if="showSuggestions"
class="suggestions"
:class="{ 'align-right': alignRight }"
style="z-index: 1"
@mouseleave="unfocus"
>
<template v-if="this.suggestions && this.suggestions.length">
<li
v-for="(s, i) in suggestions"
:key="i"
class="suggestion"
:class="{ focused: i === focusIndex }"
@mousedown="go(i)"
@mouseenter="focus(i)"
>
<a :href="s.path" @click.prevent>
<div class="suggestion-item">
<span class="page-title">{{ s.title || 'Document' }}</span>
<span v-if="s.header" class="header">{{ s.header.title }}</span>
</div>
</a>
</li>
</template>
<li v-else class="suggestion">
<div class="suggestion-item">
<span class="page-title">暂无结果</span>
</div>
</li>
</ul>
</div>
</template>
<script>
import matchQuery from './match-query';
/* global SEARCH_MAX_SUGGESTIONS, SEARCH_PATHS, SEARCH_HOTKEYS */
export default {
name: 'SearchBox',
data() {
return {
query: '',
focused: false,
focusIndex: 0,
placeholder: undefined,
SEARCH_PATHS: null,
SEARCH_HOTKEYS: ['s', '/'],
SEARCH_MAX_SUGGESTIONS: 5,
};
},
computed: {
showSuggestions() {
return this.focused && this.query && this.query.length; // && this.suggestions && this.suggestions.length;
},
suggestions() {
const query = this.query.trim().toLowerCase();
if (!query) {
return;
}
const { pages } = this.$site;
const max = this.$site.themeConfig.searchMaxSuggestions || this.SEARCH_MAX_SUGGESTIONS;
const localePath = this.$localePath;
const res = [];
for (let i = 0; i < pages.length; i++) {
if (res.length >= max) break;
const p = pages[i];
// filter out results that do not match current locale
if (this.getPageLocalePath(p) !== localePath) {
continue;
}
// filter out results that do not match searchable paths
if (!this.isSearchable(p)) {
continue;
}
if (matchQuery(query, p)) {
res.push(p);
} else if (p.headers) {
for (let j = 0; j < p.headers.length; j++) {
if (res.length >= max) break;
const h = p.headers[j];
if (h.title && matchQuery(query, p, h.title)) {
res.push(
Object.assign({}, p, {
path: p.path + '#' + h.slug,
header: h,
})
);
}
}
}
}
return res;
},
// make suggestions align right when there are not enough items
alignRight() {
const navCount = (this.$site.themeConfig.nav || []).length;
const repo = this.$site.repo ? 1 : 0;
return navCount + repo <= 2;
},
},
mounted() {
this.placeholder = this.$site.themeConfig.searchPlaceholder || '';
document.addEventListener('keydown', this.onHotkey);
},
beforeDestroy() {
document.removeEventListener('keydown', this.onHotkey);
},
methods: {
getPageLocalePath(page) {
for (const localePath in this.$site.locales || {}) {
if (localePath !== '/' && page.path.indexOf(localePath) === 0) {
return localePath;
}
}
return '/';
},
isSearchable(page) {
let searchPaths = this.SEARCH_PATHS;
// all paths searchables
if (searchPaths === null) {
return true;
}
searchPaths = Array.isArray(searchPaths) ? searchPaths : new Array(searchPaths);
return (
searchPaths.filter(path => {
return page.path.match(path);
}).length > 0
);
},
onHotkey(event) {
if (event.srcElement === document.body && this.SEARCH_HOTKEYS.includes(event.key)) {
this.$refs.input.focus();
event.preventDefault();
}
},
onUp() {
if (this.showSuggestions) {
if (this.focusIndex > 0) {
this.focusIndex--;
} else {
this.focusIndex = this.suggestions.length - 1;
}
}
},
onDown() {
if (this.showSuggestions) {
if (this.focusIndex < this.suggestions.length - 1) {
this.focusIndex++;
} else {
this.focusIndex = 0;
}
}
},
go(i) {
if (!this.showSuggestions) {
return;
}
this.$router.push(this.suggestions[i].path);
this.query = '';
this.focusIndex = 0;
},
focus(i) {
this.focusIndex = i;
},
unfocus() {
this.focusIndex = -1;
},
},
};
</script>
<style lang="stylus">
.search-box
display inline-block
position relative
margin-right 1rem
input
cursor text
width 10rem
height: 2rem
color lighten($textColor, 25%)
display inline-block
border 1px solid darken($borderColor, 10%)
border-radius 2rem
font-size 0.9rem
line-height 2rem
padding 0 0.5rem 0 2rem
outline none
transition all .2s ease
background #fff url(search.svg) 0.6rem 0.5rem no-repeat
background-size 1rem
&:focus
cursor auto
border-color $accentColor
.suggestions
background #fff
width 20rem
position absolute
top 2 rem
border 1px solid darken($borderColor, 10%)
border-radius 6px
padding 0.4rem
list-style-type none
&.align-right
right 0
.suggestion
line-height 1.4
padding 0.4rem 0.6rem
border-radius 4px
cursor pointer
a
white-space normal
color lighten($textColor, 35%)
.page-title
font-weight 600
.header
font-size 0.9em
margin-left 0.25em
&.focused
background-color #f3f4f5
a
color $accentColor
@media (max-width: $MQNarrow)
.search-box
input
cursor pointer
width 0
border-color transparent
position relative
&:focus
cursor text
left 0
width 10rem
// Match IE11
@media all and (-ms-high-contrast: none)
.search-box input
height 2rem
@media (max-width: $MQNarrow) and (min-width: $MQMobile)
.search-box
.suggestions
left 0
@media (max-width: $MQMobile)
.search-box
margin-right 0
input
left 1rem
.suggestions
right 0
@media (max-width: $MQMobileNarrow)
.search-box
.suggestions
width calc(100vw - 4rem)
input:focus
width 8rem
// by Lxh
.search-box
.suggestions
width 30rem
.suggestion
$li-border-color = #f0f0f0
border 1px solid $li-border-color
border-radius 0
padding 0
&:not(:last-child)
border-bottom none
&:first-child
border-top-left-radius 6px
border-top-right-radius 6px
&:last-child
border-bottom 1px solid $li-border-color
border-bottom-left-radius 6px
border-bottom-right-radius 6px
a
width 100%
.suggestion-item
width 100%
display flex
.page-title
flex 1
width 9rem
background-color #f7f7f7
padding 10px
display flex
flex-direction column
justify-content center
text-align center
word-break break-all
.header
flex 2
padding-left 20px
display flex
flex-direction column
justify-content center
text-align left
</style>
import get from 'lodash/get'
export default (query, page, additionalStr = null) => {
let domain = get(page, 'title', '')
if (get(page, 'frontmatter.tags')) {
domain += ` ${page.frontmatter.tags.join(' ')}`
}
if (additionalStr) {
domain += ` ${additionalStr}`
}
return matchTest(query, domain)
}
const matchTest = (query, domain) => {
const escapeRegExp = str => str.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
// eslint-disable-next-line no-control-regex
const nonASCIIRegExp = new RegExp('[^\x00-\x7F]')
const words = query
.split(/\s+/g)
.map(str => str.trim())
.filter(str => !!str)
if (!nonASCIIRegExp.test(query)) {
// if the query only has ASCII chars, treat as English
const hasTrailingSpace = query.endsWith(' ')
const searchRegex = new RegExp(
words
.map((word, index) => {
if (words.length === index + 1 && !hasTrailingSpace) {
// The last word - ok with the word being "startswith"-like
return `(?=.*\\b${escapeRegExp(word)})`
} else {
// Not the last word - expect the whole word exactly
return `(?=.*\\b${escapeRegExp(word)}\\b)`
}
})
.join('') + '.+',
'gi'
)
return searchRegex.test(domain)
} else {
// if the query has non-ASCII chars, treat as other languages
return words.some(word => domain.toLowerCase().indexOf(word) > -1)
}
}
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13"><g stroke-width="2" stroke="#aaa" fill="none"><path d="M11.29 11.71l-4-4"/><circle cx="5" cy="5" r="4"/></g></svg>
<script>
import { isActive, hashRE, groupHeaders } from '../util'
export default {
functional: true,
props: ['item', 'sidebarDepth'],
render (h,
{
parent: {
$page,
$site,
$route,
$themeConfig,
$themeLocaleConfig
},
props: {
item,
sidebarDepth
}
}) {
// use custom active class matching logic
// due to edge case of paths ending with / + hash
const selfActive = isActive($route, item.path)
const maxDepth = [
$page.frontmatter.sidebarDepth,
sidebarDepth,
$themeLocaleConfig.sidebarDepth,
$themeConfig.sidebarDepth,
1
].find(depth => depth !== undefined)
// for sidebar: auto pages, a hash link should be active if one of its child
// matches
const active = item.type === 'auto'
? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
: selfActive
const link = item.type === 'external'
? renderExternal(h, item.path, item.title || item.path)
: renderLink(h, item.path, item.title || item.path, active, undefined, item.headers)
const displayAllHeaders = $themeLocaleConfig.displayAllHeaders
|| $themeConfig.displayAllHeaders
if (item.type === 'auto') {
return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
} else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {
const children = groupHeaders(item.headers)
return [link, renderChildren(h, children, item.path, $route, maxDepth)]
} else {
return link
}
}
}
let beforeActiveLinkText = ''
function renderLink (h, to, text, active, level, headers) {
let VNode
let firstRender
if(headers && active){
firstRender = beforeActiveLinkText !== text
beforeActiveLinkText = text
}
const component = {
props: {
to,
activeClass: '',
exactActiveClass: ''
},
class: {
active,
'sidebar-link': true,
'data-no-emphasize': headers && headers.some(item => item.level < 3)
},
nativeOn: {
click: (e) => {
if (firstRender) { firstRender = false; return; }
if (e.target.className.indexOf('data-no-emphasize') === -1) return;
const child = VNode.componentOptions.children[0].elm.parentElement.nextElementSibling
if(!child) return
const originDisplay = child.style.display
child.style.display = originDisplay === 'none' ? 'block' : 'none'
}
}
}
if (level > 2) {
component.style = {
'padding-left': level + 'rem'
}
}
VNode = h('RouterLink', component, text)
return VNode
}
function renderChildren (h, children, path, route, maxDepth, depth = 1) {
if (!children || depth > maxDepth) return null
return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {
const active = isActive(route, path + '#' + c.slug)
return h('li', { class: 'sidebar-sub-header' }, [
renderLink(h, path + '#' + c.slug, c.title, active, c.level - 1),
renderChildren(h, c.children, path, route, maxDepth, depth + 1)
])
}))
}
function renderExternal (h, to, text) {
return h('a', {
attrs: {
href: to,
target: '_blank',
rel: 'noopener noreferrer'
},
class: {
'sidebar-link': true
}
}, [text, h('OutboundLink')])
}
</script>
<style lang="stylus">
.sidebar .sidebar-sub-headers
padding-left 1rem
font-size 0.95em
a.sidebar-link
font-size 1em
font-weight 400
display inline-block
color $textColor
border-left 0.25rem solid transparent
padding 0.35rem 1rem 0.35rem 1.25rem
line-height 1.4
width: 100%
box-sizing: border-box
&:hover
color $accentColor
&.active
font-weight 600
color $accentColor
border-left-color $accentColor
.sidebar-group &
padding-left 2rem
.sidebar-sub-headers &
padding-top 0.25rem
padding-bottom 0.25rem
border-left none
&.active
font-weight 500
</style>
\ No newline at end of file
<template>
<div class="contact-box">
<template v-if="currentConfig.contactItems && currentConfig.contactItems.length">
<template v-for="item in currentConfig.contactItems">
<a :key="item.name" :href="item.url" target="_blank" class="contact-item">
<img :src="item.imageUrl" width="20" height="20" />
<div class="contact-smg">
<div>{{ item.name }}</div>
</div>
</a>
</template>
</template>
<div class="contact-item" v-if="currentConfig.codeHosting && currentConfig.codeHosting.length">
<img
src="https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/74cda950-4f2d-11eb-a16f-5b3e54966275.png"
width="20"
height="20"
/>
<div class="contact-smg">
<div>
代码仓库:
<template v-for="(item, index) in currentConfig.codeHosting">
<a :key="item.url" :href="item.url" target="_blank">{{ item.name }}</a>
{{ currentConfig.codeHosting.length - index > 1 ? '' : '' }}
</template>
</div>
</div>
</div>
<div class="contact-item" v-if="currentQQGroup.length">
<img
src="https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/759713d0-4f2d-11eb-a16f-5b3e54966275.png"
width="20"
height="20"
/>
<div class="contact-smg">
<div>官方QQ交流群</div>
<template v-for="item in currentQQGroup">
<div v-if="!item.state" :key="item.number">
{{ item.prefix }}{{ item.number }} &nbsp;
<a
target="_blank"
style="text-decoration: underline"
href="https://qm.qq.com/cgi-bin/qm/qr?k=qKfkZ1A1WkW76lc97uEHyO900W7k4w4Z&jump_from=webapi"
>
点此加入
</a>
</div>
<div v-else :key="item.number">
{{ item.prefix }}{{ item.number }}{{ item.attendance || 2000 }}人已满)
</div>
</template>
</div>
</div>
<div class="contact-item">
<img
src="https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/77df7d30-4f2d-11eb-bd01-97bc1429a9ff.png"
width="20"
height="20"
/>
<div class="contact-smg">
<div>关注微信公众号</div>
<img
src="https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/78a8e7b0-4f2d-11eb-8ff1-d5dcf8779628.jpg"
width="90"
height="90"
/>
</div>
</div>
</div>
</template>
<script>
import navInject from '../mixin/navInject';
import siderbarConfig from '../config/siderbar';
export default {
mixins: [navInject],
data: () => ({
siderbarConfig,
}),
computed: {
currentConfig() {
return this.siderbarConfig[this.customNavBarKeys[this.navConfig.userNavIndex]] || {};
},
currentQQGroup() {
return [...(this.currentConfig.qq_group || [])].reverse();
},
},
};
</script>
<style>
.contact-box {
border-top: 1px solid #eee;
margin-top: 20px;
margin-bottom: 20px;
padding: 0 10px;
}
.contact-box a {
color: #42b983;
}
.contact-item {
padding-top: 30px;
padding-left: 0;
display: flex;
flex-direction: row;
}
a.contact-item {
display: flex;
padding: 0;
margin-top: 20px;
padding-left: 0;
text-decoration: none;
}
.contact-item > img {
margin: 3px 10px 0 10px;
}
.contact-smg {
display: flex;
flex-direction: column;
}
.contact-smg div {
font-size: 15px;
color: #000000;
line-height: 24px;
}
</style>
/**
* text
* target
* link // 有协议时是外链
* items
* type // link、links。
* rel
* needOutbound // 是否显示外链图标
*/
export const navbar = [
{
text: 'uni-app',
items: [
{
text: '介绍',
type: 'link',
link: '/'
},
{
text: '教程',
type: 'link',
link: '/tutorial/'
},
{
text: '全局文件',
type: 'link',
link: '/collocation/pages'
},
{
text: '组件',
type: 'link',
link: '/component/'
},
{
text: 'API',
type: 'link',
link: '/api/'
},
{
text: '插件',
type: 'link',
link: '/plugin/'
},
{
text: '工程化',
type: 'link',
link: '/worktile/'
},
{
text: '其他规范',
type: 'links',
link: 'http://www.html5plus.org/doc/h5p.html',
items: [
{
text: 'App扩展规范 HTML5 Plus',
type: 'link',
link: 'http://www.html5plus.org/doc/h5p.html'
},
{
text: '微信小程序',
type: 'link',
link: 'https://developers.weixin.qq.com/miniprogram/dev/framework/'
},
{
text: '支付宝小程序',
type: 'link',
link: 'https://docs.alipay.com/mini/developer/getting-started'
},
{
text: '百度小程序',
type: 'link',
link: 'https://smartprogram.baidu.com/docs/develop/tutorial/codedir/'
},
{
text: '字节跳动小程序',
type: 'link',
link: 'https://developer.toutiao.com/dev/cn/mini-app/develop/component/introduction/basic-component'
},
{
text: '飞书小程序',
type: 'link',
link: 'https://open.feishu.cn/document/uYjL24iN/uUDNzUjL1QzM14SN0MTN'
},
{
text: '钉钉小程序',
type: 'link',
link: 'https://developers.dingtalk.com/document/app/introduction-to-dingtalk-mini-programs'
},
{
text: 'QQ小程序',
type: 'link',
link: 'https://q.qq.com/wiki/develop/miniprogram/frame/'
},
{
text: '快手小程序',
type: 'link',
link: 'https://mp.kuaishou.com/docs/develop/frame/config/conf_appjson.html'
},
{
text: '京东小程序',
type: 'link',
link: 'https://mp-docs.jd.com/framework/'
},
{
text: '华为快应用',
type: 'link',
link: 'https://developer.huawei.com/consumer/cn/doc/development/quickApp-References/webview-component-view'
},
{
text: '360小程序',
type: 'link',
link: 'https://mp.360.cn/doc/miniprogram/dev/#/view'
},
{
text: 'Weex',
type: 'link',
link: 'http://doc.weex.io/zh/guide/introduction.html'
},
]
},
/* {
link: "https://github.com/dcloudio/uni-app",
target: "_blank",
text: "GitHub",
type: "link"
} */
]
},
{
text: 'uniCloud',
type: 'link',
link: '/uniCloud/'
},
{
text: 'HBuilder',
link: 'https://hx.dcloud.net.cn/',
type: "link",
target: '_blank',
needOutbound: false
},
{
text: 'uni 小程序 sdk',
link: 'https://nativesupport.dcloud.net.cn/UniMPDocs/SDKDownload/android',
type: "link",
target: '_blank',
needOutbound: false
},
/* {
text: '问答社区',
link: 'https://ask.dcloud.net.cn/explore/',
type: "link",
target: '_blank',
needOutbound: false
},
{
text: '插件市场',
type: "link",
target: '_blank',
link: 'https://ext.dcloud.net.cn/',
needOutbound: false
} */
]
\ No newline at end of file
const routerMap = {
'/collocation/frame/lifecycle#页面生命周期': '/tutorial/page.html#lifecycle',
'/api/lifetime': '/collocation/App.html#applifecycle',
'/collocation/frame/lifecycle#应用生命周期': '/collocation/App.html#applifecycle',
'/collocation/frame/lifetime': '/collocation/App.html#applifecycle',
'/collocation/frame/lifecycle': '/collocation/App.html#applifecycle',
'/collocation/frame/communication': '/tutorial/page.html#页面通讯',
'/collocation/frame/lifecycle#page': '/tutorial/page.html#lifecycle',
'/collocation/frame/lifecycle#component': '/tutorial/page.html#componentlifecycle',
'/collocation/frame/timer': '/api/timer.html',
'/collocation/auto/hbuilderx-extension/index': '/worktile/auto/hbuilderx-extension/',
'/collocation/auto/hbuilderx-extension/': '/worktile/auto/hbuilderx-extension/',
'/collocation/auto/quick-start': '/worktile/auto/quick-start.html',
'/collocation/auto/uniapp-cli-project': '/worktile/auto/uniapp-cli-project.html',
'/collocation/i18n': '/worktile/i18n.html',
'/collocation/env': '/tutorial/env.html',
'/collocation/ssr': '/tutorial/ssr.html',
'/ssr': '/tutorial/ssr.html',
'/ssr/': '/tutorial/ssr.html',
'/collocation/frame/window': '/tutorial/page.html#getapp',
'/collocation/frame/window#getcurrentpages': '/tutorial/page.html#getcurrentpages',
'/collocation/auto/api': '/worktile/auto/api.html',
'/collocation/frame/log': '/api/log.html',
'/component/mp-weixin-plugin': '/tutorial/mp-weixin-plugin.html',
'/component/uniui': '/component/uniui/uni-ui.html',
'/frame': '/tutorial/',
'/frame#renderjs': '/tutorial/renderjs.html',
'/frame#css变量': '/tutorial/syntax-css.html#css-变量',
'/frame#css引入静态资源': '/tutorial/page-static-assets.html',
'/frame#js文件引入': '/tutorial/page-script.html',
'/frame#字体图标': '/tutorial/syntax-css.html#字体图标',
'/frame#wxs': '/tutorial/miniprogram-subject.html#wxs',
'/frame#flex布局': '/tutorial/syntax-css.html#flex-布局',
'/frame#npm支持': '/tutorial/page-script.html#npm支持',
'/frame#尺寸单位': '/tutorial/syntax-css.html#尺寸单位',
'/frame#目录结构': '/tutorial/project.html#目录结构',
'/frame#路由跳转': '/tutorial/page.html#路由跳转',
'/frame#小程序组件支持': '/tutorial/miniprogram-subject.html',
'/frame#小程序自定义组件支持': '/tutorial/miniprogram-subject.html#小程序自定义组件支持',
'/frame#判断平台': '/worktile/running-env.html#判断平台',
'/frame#typescript-支持': '/tutorial/typescript-subject.html#typescript-支持',
'/frame#全局样式与局部样式': '/tutorial/syntax-css.html#全局样式与局部样式',
'/frame#注意事项-1': '/tutorial/renderjs.html#注意事项',
'/api/ui/language': '/api/ui/locale.html',
'/api/ad/rewarded-video-ad': '/api/a-d/rewarded-video.html',
'/api/a-d/rewarded-video-ad': '/api/a-d/rewarded-video.html',
'/api/ad/interstitial-ad': '/api/a-d/interstitial.html',
'/api/ui/navigate': '/api/router.html',
'/platform': '/tutorial/platform.html',
'/nvue-event': '/tutorial/nvue-event.html',
'/api/extend/native-plugin': '/plugin/native-plugin.html',
'/use-html5plus': '/tutorial/use-html5plus.html',
'/vue-components': '/tutorial/vue-components.html',
'/vue-components.html': '/tutorial/vue-components.html',
'/vue-basics': '/tutorial/vue-basics.html',
'/vue-api': '/tutorial/vue-api.html',
'/vue-vuex': '/tutorial/vue-vuex.html',
'/vue3-api': '/tutorial/vue3-api.html',
'/vue3-basics': '/tutorial/vue3-basics.html',
'/vue3-vuex': '/tutorial/vue3-vuex.html',
'/vue3-components': '/tutorial/vue3-components.html',
'/migration-to-vue3': '/tutorial/migration-to-vue3.html',
'/nvue-outline': '/tutorial/nvue-outline.html',
'/nvue-api': '/tutorial/nvue-api.html',
'/nvue-css': '/tutorial/nvue-css.html',
'/uniCloud/database': '/uniCloud/clientdb.html',
'/uniCloud/uni-clientDB': '/uniCloud/clientdb.html',
'/uniCloud/uni-data-picker': '/component/uniui/uni-data-picker.html',
'/plugin/hybrid': '/hybrid.html',
'/adapt': '/tutorial/adapt.html',
'/share': '/api/plugins/share.html',
'/performance': '/tutorial/performance.html',
'/use-weex': '/tutorial/nvue-outline.html',
'/uni_modules': '/plugin/uni_modules.html',
'/snippet': '/tutorial/snippet.html',
'/store': '/tutorial/store.html',
}
export default ({ fullPath, path, hash }) => {
fullPath = decodeURIComponent(fullPath)
const matchFullPath = routerMap[fullPath.replace('?id=', '#')];
if (matchFullPath) {
return {
path: matchFullPath,
replace: true
}
}
const matchPath = routerMap[path]
if (matchPath) {
return {
path: matchPath,
hash,
replace: true
}
}
if (path.indexOf('/app-') === 0 || path.indexOf('/android-') === 0 || path.indexOf('/ios-') === 0) {
return {
path: `/tutorial${path}`,
hash,
replace: true
}
}
}
\ No newline at end of file
import uniapp from './uni-app';
import uniCloud from './uniCloud';
export default {
"uni-app": uniapp,
uniCloud
}
export default {
contactItems: [
{
name: 'uniCloud Web控制台',
url: 'https://unicloud.dcloud.net.cn',
imageUrl: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/7962e8e0-4f2d-11eb-a16f-5b3e54966275.jpg'
},
{
name: '论坛',
url: 'https://ask.dcloud.net.cn/explore/',
imageUrl: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/73fc4f90-4f2d-11eb-a16f-5b3e54966275.png'
},
{
name: 'uniAD',
url: 'https://uniad.dcloud.net.cn',
imageUrl: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/765d9820-4f2d-11eb-bd01-97bc1429a9ff.png'
},
{
name: 'uni统计',
url: 'https://tongji.dcloud.net.cn/',
imageUrl: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/77159d80-4f2d-11eb-a16f-5b3e54966275.png'
}
],
codeHosting: [
{
name: '码云',
url: 'https://gitee.com/dcloud/uni-app'
},
{
name: 'GitHub',
url: 'http://github.com/dcloudio/uni-app'
}
],
qq_group: [
{
"number": "531031261",
"state": 1,
"prefix": "群1"
},
{
"number": "901474938",
"state": 1,
"prefix": "群2"
},
{
"number": "773794803",
"state": 1,
"prefix": "群3"
},
{
"number": "942702595",
"state": 1,
"prefix": "群4"
},
{
"number": "731951419",
"state": 1,
"prefix": "群5"
},
{
"number": "697264024",
"state": 1,
"prefix": "群6"
},
{
"number": "942061423",
"state": 1,
"prefix": "群7"
},
{
"number": "695442854",
"state": 1,
"prefix": "群8"
},
{
"number": "775128777",
"state": 1,
"prefix": "群9"
},
{
"number": "959059626",
"state": 1,
"prefix": "群10"
},
{
"number": "296811328",
"state": 1,
"prefix": "群11"
},
{
"number": "884860657",
"state": 1,
"prefix": "群12"
},
{
"number": "699478442",
"state": 1,
"prefix": "群13"
},
{
"number": "465953250",
"state": 1,
"prefix": "群14"
},
{
"number": "516984120",
"state": 1,
"prefix": "群15"
},
{
"number": "719211033",
"state": 1,
"prefix": "群16"
},
{
"number": "951348804",
"state": 1,
"prefix": "群17"
},
{
"number": "698592271",
"state": 1,
"prefix": "群18"
},
{
"number": "165657124",
"state": 1,
"prefix": "群19"
},
{
"number": "165796402",
"state": 1,
"prefix": "群20"
},
{
"number": "717019120",
"state": 1,
"prefix": "群21"
},
{
"number": "687186952",
"state": 1,
"prefix": "群22"
},
{
"number": "599958679",
"state": 1,
"prefix": "群23"
},
{
"number": "672494800",
"state": 1,
"prefix": "群24"
},
{
"number": "165297000",
"state": 1,
"prefix": "群25"
},
{
"number": "147867597",
"state": 1,
"prefix": "群26"
},
{
"number": "811363410",
"state": 1,
"prefix": "群27"
},
{
"number": "202965481",
"state": 1,
"prefix": "群29"
},
{
"number": "371046920",
"state": 1,
"prefix": "群30"
},
{
"number": "567471669",
"state": 1,
"prefix": "群31"
},
{
"number": "166188631",
"state": 1,
"prefix": "群32"
},
{
"number": "498071674",
"state": 1,
"prefix": "群33"
},
{
"number": "530305531",
"state": 1,
"prefix": "群34"
},
{
"number": "713420817",
"state": 1,
"prefix": "群35"
},
{
"number": "166188776",
"state": 0,
"prefix": "群28"
}
]
}
\ No newline at end of file
export default {
contactItems: [
{
name: 'uniCloud Web控制台',
url: 'https://unicloud.dcloud.net.cn',
imageUrl: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/7962e8e0-4f2d-11eb-a16f-5b3e54966275.jpg'
},
{
name: '论坛',
url: 'https://ask.dcloud.net.cn/explore/',
imageUrl: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/73fc4f90-4f2d-11eb-a16f-5b3e54966275.png'
},
{
name: 'uniAD',
url: 'https://uniad.dcloud.net.cn',
imageUrl: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/765d9820-4f2d-11eb-bd01-97bc1429a9ff.png'
},
{
name: 'uni统计',
url: 'https://tongji.dcloud.net.cn/',
imageUrl: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/77159d80-4f2d-11eb-a16f-5b3e54966275.png'
}
],
qq_group: [
{
"number": "1012245137",
"state": 1,
"prefix": "群1"
},
{
"number": "749911289",
"state": 1,
attendance: 1000,
"prefix": "群2"
},
{
"number": "599819864",
"state": 1,
attendance: 1000,
"prefix": "群3"
},
{
"number": "641753405",
"state": 0,
"prefix": "群4"
},
]
}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
module.exports = {
extend: '@vuepress/theme-default',
plugins: [
['container', {
type: 'preview',
validate: (params) =>{
// return params.trim().match(/^preview\s+(.*)$/);
return params.trim().match(/^preview/);
},
render: (tokens, idx,otps,event)=> {
var m = tokens[idx].info.trim().match(/^preview\s+(.*)$/);
if (tokens[idx].nesting === 1) {
// opening tag
return `<CodeSimulator class="code" src="${m && m.length > 0?m[1]:''}">`;
} else {
// closing tag
return `</CodeSimulator>`;
}
}
}],
'@vuepress/back-to-top'
]
}
<template>
<div class="theme-container">
<div class="theme-default-content">
<h1>404</h1>
<blockquote>{{ getMsg() }}</blockquote>
<RouterLink to="/">Take me home.</RouterLink>
</div>
</div>
</template>
<script>
const msgs = [
`There's nothing here.`,
`How did we get here?`,
`That's a Four-Oh-Four.`,
`Looks like we've got some broken links.`,
];
export default {
methods: {
getMsg() {
return msgs[Math.floor(Math.random() * msgs.length)];
},
},
mounted() {
const xhr = new XMLHttpRequest();
xhr.open('post', 'https://b1ecec17-5c3f-4de9-8b5b-ab739a9a47d5.bspapp.com/unidocs-zh-stat');
xhr.setRequestHeader('content-type', 'application/json;charset=utf-8');
xhr.send(
JSON.stringify({
params: {
fullPath: this.$route.fullPath,
hash: this.$route.hash,
path: this.$route.path,
params: this.$route.params,
query: this.$route.query,
},
})
);
},
};
</script>
此差异已折叠。
export default {
inject: ['navConfig', 'customNavBar', 'changeUserNav', 'customNavBarKeys'],
computed: {
showSubNavBar() {
return !!this.customNavBar[this.navConfig.userNavIndex].items
},
mainNavBarText() {
return this.customNavBar[this.navConfig.userNavIndex].text
},
subNavBarText() {
const curNavBar = this.customNavBar[this.navConfig.userNavIndex]
const curLink = (this.$page.path.match(/\/(\w+)+\/*/) || [])[1]
const item = curNavBar.items ? curNavBar.items.filter(
item => item.type === 'link' && item.link.indexOf(curLink) !== -1
)[0] : curNavBar
return item ? item.text : curNavBar.items[0].text
}
}
}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
// 布局
$accentColor = #42b983
$contentWidth = 1200px
$navbarHeight = 9rem
$navbar-sub-navbar-height = 5rem
$navbar-background-color = #f7f7f7
$search-container-color = #f5f6f7
\ No newline at end of file
此差异已折叠。
此差异已折叠。
---
pageClass: custom-page-class
---
```uni-app``` 是一个使用 [Vue.js](https://vuejs.org/) 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
`DCloud`公司拥有900万开发者、数百万应用、12亿手机端月活用户、数千款uni-app插件、70+微信/qq群。阿里小程序工具官方内置uni-app([详见](https://docs.alipay.com/mini/ide/0.70-stable)),腾讯课堂官方为uni-app录制培训课程([详见](https://ask.dcloud.net.cn/article/35640)),开发者可以放心选择。
`DCloud`公司拥有900万开发者、数百万应用、12亿手机端月活用户、数千款uni-app插件、70+微信/qq群。阿里小程序工具官方内置uni-app([详见](https://opendocs.alipay.com/mini/ide/overview)),腾讯课堂官方为uni-app录制培训课程([详见](https://ask.dcloud.net.cn/article/35640)),开发者可以放心选择。
`uni-app`在手,做啥都不愁。即使不跨端,```uni-app```也是更好的小程序开发框架([详见](https://ask.dcloud.net.cn/article/35947))、更好的App跨平台框架、更方便的H5开发框架。不管领导安排什么样的项目,你都可以快速交付,不需要转换开发思维、不需要更改开发习惯。
......
......@@ -13,6 +13,7 @@
- [钉钉小程序](https://developers.dingtalk.com/document/app/introduction-to-dingtalk-mini-programs)
- [QQ小程序](https://q.qq.com/wiki/develop/miniprogram/frame/)
- [快手小程序](https://mp.kuaishou.com/docs/develop/frame/config/conf_appjson.html)
- [京东小程序](https://mp-docs.jd.com/framework/)
- [华为快应用](https://developer.huawei.com/consumer/cn/doc/development/quickApp-References/webview-component-view)
- [360小程序](https://mp.360.cn/doc/miniprogram/dev/#/view)
- [Weex](http://doc.weex.io/zh/guide/introduction.html)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册