全文检索移动端适配

This commit is contained in:
结发受长生 2019-07-08 21:14:40 +08:00
parent 0917a4c8ed
commit 0e94c2d863
5 changed files with 97 additions and 59 deletions

View File

@ -1,20 +1,25 @@
<div class="page-modal js-search-box" ref="fullTextSearch" > <div class="page-modal" id="search-panel" ref="fullTextSearch" >
<a class="close js-modal-close" href="javascript:;"><i class="icon icon-close"></i></a> <div class="search-container">
<div class="search"> <a class="close js-modal-close" href="javascript:;"><i class="icon icon-close"></i></a>
<div class="search-input-icon"> <div class="search">
<i class="icon icon-search"></i> <div class="search-input-icon">
<i class="icon icon-search"></i>
</div>
<div class="search-input" >
<input placeholder="搜索所有文章" type="text" v-model="fullTextSearchWords" >
</div>
</div> </div>
<div class="search-input" > <div class="search-result">
<input placeholder="搜索所有文章" type="text" v-model="fullTextSearch.words" >
</div> <div class="search-result-item" v-for="(item,index) in fullTextSearchItems" :key="index">
</div> <a v-text="item.title" :href="themeConfig.root + item.path"></a>
<div class="search-result"> <div v-html="item.content"></div>
<div class="search-result-item" v-for="(item,index) in fullTextSearchItems" :key="index"> </div>
<a v-text="item.title" :href="themeConfig.root + item.path"></a> <div class="more-item tip" v-show="fullTextSearchItems.hasMore" @click="loadSearchResult">
<div v-html="item.content"></div> <i class="icon icon-chevron-up"></i>
</div> </div>
<div class="more-item" v-show="fullTextSearchItems.hasMore" @click="loadMoreSearchResult"> <div class="tip" v-show="fullTextSearchItems.isLoading || fullTextSearchTip"
<i class="icon icon-chevron-up"></i> v-text="fullTextSearchTip || '正在搜索...'"></div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -341,4 +341,20 @@
} }
} }
} }
}
#search-panel {
width: 100%;
height: 100%;
top: 0;
left: 0;
transform: none;
.search-container {
display: flex;
width: 100%;
height: 100%;
flex-direction: column;
.search-result {
flex-grow: 1;
}
}
} }

View File

@ -61,7 +61,6 @@
&.in { &.in {
display: block; display: block;
visibility: visible;
opacity: 1; opacity: 1;
} }
@ -79,7 +78,7 @@
} }
.mask { .mask {
visibility: hidden; display: none;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
@ -93,7 +92,7 @@
pointer-events: none; pointer-events: none;
transition: .3s ease-in-out; transition: .3s ease-in-out;
&.in { &.in {
visibility: visible; display: block;
pointer-events: auto; pointer-events: auto;
opacity: .3; opacity: .3;
} }

View File

@ -245,13 +245,12 @@ label.bui-switch-label {
} }
} }
.js-search-box { #search-panel {
width: 500px;
top: 10%;
transform: translate(-50%,0);
.search { .search {
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
background: #f5f5f5;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
width: 500px;
display: flex; display: flex;
line-height: 40px; line-height: 40px;
.search-input-icon { .search-input-icon {
@ -269,9 +268,9 @@ label.bui-switch-label {
} }
} }
.search-result { .search-result {
height: 600px; max-height: 600px;
width: 500px;
overflow-y: auto; overflow-y: auto;
position: relative;
.search-result-item { .search-result-item {
text-align: left; text-align: left;
border-bottom: 1px dashed $colorC; border-bottom: 1px dashed $colorC;
@ -280,10 +279,16 @@ label.bui-switch-label {
border-bottom-color: $colorA; border-bottom-color: $colorA;
} }
} }
.tip {
text-align: center;
}
.more-item { .more-item {
cursor: pointer; cursor: pointer;
text-align: center; transform: rotate(180deg) translateY(60px);
transform: rotate(180deg) background: linear-gradient(-180deg,$colorBg 10%,rgba(255, 255, 255, 0) 100%);
} position: absolute;
height: 70px;
width: 100%;
}
} }
} }

View File

@ -31,9 +31,10 @@ new Vue({
fullTextSearch: { fullTextSearch: {
pageNum: 1, pageNum: 1,
limit: 10, limit: 10,
words: null
}, },
fullTextSearchWords: null,
fullTextSearchItems: [], fullTextSearchItems: [],
fullTextSearchTip: undefined,
waifu: { waifu: {
tip: null, // 提示语文字 tip: null, // 提示语文字
tipOpacity: 0, // 提示语框透明度 tipOpacity: 0, // 提示语框透明度
@ -93,12 +94,26 @@ new Vue({
this.$refs.fullTextSearch.classList.add('in') this.$refs.fullTextSearch.classList.add('in')
this.$refs.mask.classList.add('in') this.$refs.mask.classList.add('in')
}, },
loadMoreSearchResult() { loadSearchResult() {
this.fullTextSearch.pageNum ++ this.fullTextSearch.pageNum ++
axios.get(window.themeConfig.root + 'api/common/search', {params: this.fullTextSearch}).then(res => { this.fullTextSearchItems.isLoading = true
this.fullTextSearchTip = undefined
let params = Object.assign({}, this.fullTextSearch)
params.words = this.fullTextSearchWords
axios.get(/*window.themeConfig.root + 'api/common/search'*/ 'http://localhost:3301/common/search', {params}).then(res => {
this.fullTextSearchItems.isLoading = false
fullTextSearchTimer = null
let result = res.data let result = res.data
if(!Array.isArray(result.data) || !result.data.length) {
this.fullTextSearchTip = '未搜索到匹配文章'
} else {
this.fullTextSearchItems.push(...result.data)
}
this.fullTextSearchItems.hasMore = (result.total > this.fullTextSearch.pageNum * this.fullTextSearch.limit) this.fullTextSearchItems.hasMore = (result.total > this.fullTextSearch.pageNum * this.fullTextSearch.limit)
this.fullTextSearchItems.push(...result.data) }).catch(err => {
this.fullTextSearchTip = '加载失败, 请刷新重试'
this.fullTextSearchItems.isLoading = false
throw err
}) })
}, },
searchKeydown(event) { searchKeydown(event) {
@ -138,31 +153,29 @@ new Vue({
}) })
} }
}, },
fullTextSearch: { fullTextSearchWords (newVal, oldVal) {
deep: true, this.fullTextSearchItems.hasMore = false
handler(newVal, oldVal) { this.fullTextSearchItems.isLoading = false
if(!newVal.words) { this.fullTextSearchTip = undefined
return this.fullTextSearchItems.splice(0, this.fullTextSearchItems.length)
} if(fullTextSearchTimer) {
if(fullTextSearchTimer) { clearTimeout(fullTextSearchTimer)
clearTimeout(fullTextSearchTimer) fullTextSearchTimer = null
} }
fullTextSearchTimer = setTimeout(() => { if(!newVal) {
this.fullTextSearchItems.length = 0 return
axios.get(window.themeConfig.root + 'api/common/search', {params: newVal}).then(res => { }
let result = res.data this.fullTextSearch.pageNum = 0
this.fullTextSearchItems.hasMore = (result.total > this.fullTextSearch.pageNum * this.fullTextSearch.limit) fullTextSearchTimer = setTimeout(() => {
this.fullTextSearchItems.push(...result.data) this.fullTextSearchItems.splice(0, this.fullTextSearchItems.length)
}) this.loadSearchResult()
}, 1000) }, 500)
}
} }
}, },
mounted () { mounted () {
axios.get(window.themeConfig.root + 'content.json?t=' + (+ new Date())) axios.get(window.themeConfig.root + 'content.json').then((res)=>{
.then((res)=>{
this.items = res.data this.items = res.data
}).catch((err) => { }).catch(err => {
console.warn('加载文章列表失败') console.warn('加载文章列表失败')
}) })
this.showMessage(welcomeMessage(), 6000) this.showMessage(welcomeMessage(), 6000)
@ -238,28 +251,28 @@ function welcomeMessage() {
} }
const waifuTools = { const waifuTools = {
"tools.photo"() { 'tools.photo'() {
// 生成canvas快照 // 生成canvas快照
window.Live2D.captureName = 'Kesshouban.png' window.Live2D.captureName = 'Kesshouban.png'
window.Live2D.captureFrame = true window.Live2D.captureFrame = true
}, },
"tools.close"() { 'tools.close'() {
// 隐藏看板娘 // 隐藏看板娘
setTimeout(function() { setTimeout(function() {
document.querySelector('.waifu').style.display = 'none' document.querySelector('.waifu').style.display = 'none'
localStorage.setItem('hideWaifu', true) localStorage.setItem('hideWaifu', true)
}, 1300) }, 1300)
}, },
"tools.eye"() { 'tools.eye'() {
// 切换到夜间模式 // 切换到夜间模式
document.querySelector('.mid-col').classList.remove('hide') document.querySelector('.mid-col').classList.remove('hide')
let night = document.querySelector('body').classList.toggle('night') let night = document.querySelector('body').classList.toggle('night')
localStorage.setItem('night', night) localStorage.setItem('night', night)
}, },
"tools.info"() { 'tools.info'() {
window.open('https://github.com/xiazeyu/live2d-widget.js') window.open('https://github.com/xiazeyu/live2d-widget.js')
}, },
"tools.chart"() { 'tools.chart'() {
// 一言 // 一言
axios.get(`${window.themeConfig.root}api/common/hitokoto?length=40&format=json`).then(res => { axios.get(`${window.themeConfig.root}api/common/hitokoto?length=40&format=json`).then(res => {
this.showMessage(res.data.hitokoto + (res.data.from?`  ——${res.data.from}`:'')) this.showMessage(res.data.hitokoto + (res.data.from?`  ——${res.data.from}`:''))