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