1. 程式人生 > >微信小程式的搜尋高亮、自定義導航條等踩坑記錄

微信小程式的搜尋高亮、自定義導航條等踩坑記錄

原文地址: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>