微信小程式的搜尋高亮、自定義導航條等踩坑記錄
原文地址:https://oomabc.com/articledetail?atclid=7421fe13daad46389791463f51d3395d
前言
我在寫這個部落格的小程式過程中,遇到了很多的問題。之前斷斷續續也寫過不少JavaScript和css,不過都是半吊子。所以在看了一會小程式demo程式碼,就開工了。雖然在一天之後就基本完成了大體功能框架,但依舊在細節上碰到了不少問題。本部落格會將我遇到的一些問題和自己的解決方案貼在下面,純粹記錄一下。
圖片
搜尋高亮
不管是電商網站還是部落格,亦或者是招聘網站,通常都少不了搜尋功能。而搜尋通常都會有一個基礎應用,那就是關鍵字高亮,因為輸入的關鍵字可能包含多個詞語,而當多個詞語命中對應結果時,這幾個詞語可能不是連續出現,所以這些高亮通常是後端介面通過搜尋引擎框架實現。
在HTML中,後端在返回的結果資料中,用標籤(例如:<span class="keyword">需要高亮的關鍵字</span>)將命中的關鍵字包起來,然後前端通過css樣式將這些關鍵字進行特殊標記。
圖片
按照這個思路,依舊是通過後端將命中關鍵字用小程式的<text class="keyword"></text>標籤包起來,前端通過樣式對其進行高亮。很遺憾,小程式直接將這段文字連同標籤一起展示了,而且網上也沒有查到讓標籤不展示的方法,所以這個思路行不通。
在小程式中,我們可以通過wx:for來實現標籤的動態生成,然後根據具體引數來確定text標籤是否需要新增高亮class。
後端依舊將高亮的關鍵字進行特殊標記,我這裡使用HHtextHHS和HHtextHHE作為高亮的開始和結束標籤,然後通過js進行字串分割,最終返回的資料結構如下:
[
{content : '重溫', type : 0}, //content就是要顯示的文字內容,type=0表示不高亮
{content : 'Java', type : 1}, //type=1表示要高亮
{content : '設計模式——', type : 0},
{content : '工廠', type : 1},
{content : '模式', type : 0}
]
實現帶高亮標籤的字串轉為陣列的js方法如下:
//入參非空判斷在上層已處理
splitTitle : function(s) {
//儲存最終返回的結果
var rslist = [];
//根據高亮開始標籤進行字串分割
var arr1 = s.split('HHtextHHS');
//遍歷分割之後的每一個字串,進行結束標籤判斷
for (var i in arr1) {
var word1 = arr1[i];
//過濾空字串
if (word1 && word1.length > 0) {
//如果有結束標籤,則進行高亮字串擷取,並設定高亮標誌位
var indexEnd = word1.indexOf('HHtextHHE');
if (indexEnd >= 0) {
rslist.push({
content: word1.substring(0, indexEnd),
type: 1
});
//剩餘不需要高亮
//注意:這裡的處理方式是基於沒有標籤巢狀的情況,如果有巢狀,這裡需要另寫邏輯
var wordEnd = word1.substring(indexEnd + 9);
if (wordEnd && wordEnd.length > 0) {
rslist.push({
content: wordEnd,
type: 0
});
}
} else {//沒有結束標籤,則表示當前字串不是需要高亮的
rslist.push({
content: word1,
type: 0
});
}
}
}
return rslist;
}
對應在wxml中,迴圈顯示這個陣列物件的標籤寫法如下:
<!-- 這裡的splitTitleList就是上面的js方法返回的陣列物件 -->
<text class="articleTitle">
<text wx:for="{{splitTitleList}}">
<text class="{{item.type == 1 ? 'keywordHighLight' : ''}}">{{item.content}}</text>
</text>
</text>
高亮樣式就是很簡單的wxss:
.keywordHighLight{
color : red;
}
搜尋框放大鏡icon
圖片
通常的搜尋輸入框都會有一個放大鏡進行icon標記,既簡介又功能清晰。所以,我也想在自己的小程式中也實現這個樣式,之前寫類似的前端程式碼很少,所以我打算通過background-image來引入放大鏡的圖示。 結果很遺憾:
template/topSearch.wxss 中的本地資源圖片無法通過 WXSS 獲取,可以使用網路圖片,或者 base64,或者使用<img>標籤。
請參考文件:https://mp.weixin.qq.com/debug/wxadoc/dev/qa.html#%E6%9C%AC%E5%9C%B0%E8%B5%84%E6%BA%90%E6%97%A0%E6%B3%95%E9%80%9A%E8%BF%87-css-%E8%8E%B7%E5%8F%96
39 | margin-left: 15px;
40 |
> 41 | background-image: url('/image/search.pn');
| ^
42 | }
43 |
44 | .searchIconImg{
微信小程式提醒我們,WXSS無法直接引入本地圖片,只能使用網路圖片或者以Base64格式,或者在WXML中用<img>引入。
所以,我就嘗試在WXML中,直接用style的行內樣式通過background-image引入圖片。嘿嘿,很簡單的通過view和input兩個標籤實現了圖示顯示,而且微信開發者工具中可以正常顯示並除錯(不過,input標籤有個bug,會顯示兩個圖示)。最終經過一番折騰,終於進入真機除錯環節,結果依舊是很遺憾,在手機上無法顯示這些圖片,而且最終稽核釋出之後,手機端還是無法顯示。
這下終於明白當初那些提示的含義了,接下來我就使用image試試。結果確實是可以的,不過要進行樣式微調。大概的WXML和樣式如下:
<view class="topSearchInputOuter">
<img src="/image/search.png" class="searchIconImg">
<input class="topSearchInput" value="{{queryWord}}" focus="true" auto-focus="true" name="topSearchInput" placeholder=" 熱門關鍵字" bindconfirm="searchArticles">
</view>
.topSearchInput{
font-size: 13px;
border: 0px solid #EFEFEF;
width: 220px;
line-height: 33px;
height : 33px;
color : gray;
padding-left : 5px;
}
.topSearchInputOuter{
background-color: #EFEFEF;
border-radius : 15px;
padding-left : 8px;
width : 240px;
line-height : 33px;
display: flex;
}
.searchIconImg{
width : 15px;
height : 15px;
vertical-align: middle;
justify-content: center;
margin-top:9px;
}
自定義狀態列
在實現狀態列搜尋功能的時候,還遇到的另一個問題就是,微信預設狀態列是不允許修改的。如果需要自定義狀態列,需要在app.json檔案的window引數中,設定navigationStyle為custom。
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "歡迎訪問OoM技術部落格",
"navigationBarTextStyle": "black",
"backgroundColor": "#f1e8e8",
"navigationStyle": "custom" //這裡設定狀態列(導航欄)樣式為自定義
}
這樣一來,頂部除了微信的膠囊按鈕之外,一片清爽。
不過這樣一來,我們就需要自己實現頂部狀態列+導航條的裝置自適應功能了。由於我也不是專業的前端,因此網上搜尋了針對全面屏和非全面屏兩種裝置的自適應方案。
通過判斷裝置是否是全面屏(iPhone X),進行狀態列高度和導航欄高度動態調整。js程式碼如下:
var vm = this;
wx.getSystemInfo({ //wx提供的獲得裝置系統資訊的方法
success: function (res) {
let totalTopHeight = 68
if (res.model.indexOf('iPhone X') !== -1) {
totalTopHeight = 88
} else if (res.model.indexOf('iPhone') !== -1) {
totalTopHeight = 64
}
var statusBar = {};
//設定狀態列相關引數
statusBar.statusBarHeight = res.statusBarHeight;
statusBar.titleBarHeight = totalTopHeight - res.statusBarHeight;
statusBar.queryWord = vm.globalData.searchDefaultPlacehoder;
//設定全域性引數,其他頁面通過 const app = getApp();app.globalData.statusBar 獲得
vm.globalData.statusBar = statusBar;
},
fail: function() {
vm.globalData.statusBar = {
statusBarHeight : 0,
titleBarHeight : 0
};
}
});
對應的在WXML中的使用,下面給出模板化應用的例子:
<template name="topNavTmp">
<view class="topNavView" style="padding-top: 0px; height :0px">
<view class="header" style="">
<!-- 狀態列 --->
<view class="status-bar" style="height:{{barStatus.statusBarHeight}}px"></view>
<!-- 導航欄 --->
<view class="title-bar" style="height:{{barStatus.titleBarHeight}}px; line-height : {{barStatus.titleBarHeight}}px;">
<!-- 這裡是頂部的返回和home按鈕 -->
<view class="topNavLeft">
<view class="topNav-one"><img bindtap="clickAndBack" class="topNavImg" src="/image/back-1.png"></view>
<view class="topNav-sep"></view>
<view class="topNav-two"><img bindtap="clickAndHome" class="topNavImg" src="/image/home-1.png"></view>
</view>
<!-- 標題 -->
{{barStatus.topNavTitle}}
<view class="tablet"></view>
</view>
</view>
</view>
<!-- 將topNavView的fixed樣式,用同樣高度頂下去,不然後面的樣式會浮上來 -->
<view style="height : {{barStatus.statusBarHeight+barStatus.titleBarHeight}}px; text-align : center;"></view>
</template>
在引用的頁面使用:
<!-- 在其它頁面引入模板的使用 -->
<import src="/template/topNav.wxml">
<!-- 這裡使用模板,傳入引數 -->
<template is="topNavTmp" data="{{barStatus}}"></template>