之前已经为博客的PC端界面添加了搜索功能,用起来效果不错,不过美中不足的是,使用手机访问的时候并不能使用搜索功能。这几天折腾了一下,终于给移动端界面上也加上了搜索功能~这里来记录一下实现方法。
之前为博客添加搜索功能的方法见:
为Hexo博客Yilia主题添加本地站内搜索功能
要为移动端添加搜索功能,主要就是添加搜索框及搜索结果HTML样式及添加相关JS代码。
添加搜索框及搜索结果区
当前主题在移动端的布局中,点击左上角的菜单按钮就会弹出一个显示友情链接、标签等信息的叠层,综合看下来将搜索框添加在这个位置较合适,最终的效果如图:
这里的搜索框和PC端基本是一样的,只是样式上做了些变化,使得整体效果更和谐。找到合适的位置添加搜索框及搜索结果区的HTML代码即可:
1 2 3 4 5 6 7 8
| <form id="search-form_mobile" class="search_mobile"> <input type="text" id="st-search-input_mobile" name="q" results="0" class="st-default-search-input_mobile" maxlength="50" placeholder="Search..." autocomplete="off" autocorrect="off"> <i class="fa fa-times" onclick="resetSearch_mobile()"></i> <p id="search_hint" class="search-hint">向右滑动结果打开链接~</p> <div id="local-search-result_mobile"></div> <p class="no-result">No results found <i class="fa fa-spinner fa-pulse"></i></p> <p class="loading-xml">Loading XML File... <i class="fa fa-spinner fa-pulse"></i></p> </form>
|
布局和PC端的稍有差异,搜索结果区和搜索框放在了同一个form
里面。CSS样式此处从略,如有兴趣可参考源文件:search.styl
添加JS代码
此主题移动端的时候使用的JS文件为mobile.js
(PC端是pc.js
),按照PC端的做法添加相关代码即可,注意搜索框等的名字要改为对应的移动端名字。这样修改后是可以实现基本功能了,然而用起来会有各种Bug,这两天的时间就主要花在解决这些Bug上了……
解决触摸无响应问题
直接把代码移植过来的第一个问题就是,在手机上那个搜索框实际上是没有用的,无法点击进行输入……具体原因并不清楚,只找到了可用的解决方案。在JS文件search
函数中添加以下代码:
1 2 3 4 5 6 7 8
| inputArea.addEventListener("touchstart", function(){ inputArea.focus(); }, false);
resetButton.addEventListener("touchstart", function(){ $resetButton.click(); }, false);
|
监听touchstart
事件,并通过程序触发focus
及click
事件。
解决滚动异常问题
加上以上代码后可以搜索了,只是搜索结果的滚动有各种奇怪的问题……比如只有输入单个字符的时候可以滚动、会发生点击穿透导致后面的页面滚动、只能按住标题进行滚动等等……各种尝试后决定不去解决这些问题了,直接监听触摸事件,自己重写滚动响应及滑动打开的代码。
基本思路是这样的:
- 在
touchstart
事件中记录触摸开始的坐标点,并且判断是按在了哪个搜索结果条目上;
- 在
touchmove
事件中获取手指移动的方向,判断是进行垂直滚动还是水平移动搜索条目(用于打开搜索结果),之后修改对应元素的marginTop
或marginLeft
属性即可实现界面元素的移动;
- 最后在
touchend
事件中判断是否发生了滑动打开链接事件,如果有的话打开对应链接。
需要注意的是,要调用preventDefault()
来阻止触摸事件的传递,以避免各种奇怪的问题。除了基本逻辑外,还做了些处理让视觉效果更好看些,具体见以下的实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| TouceArea.onscroll = function(e) { e.preventDefault(); }
TouceArea.ontouchstart = function(e) { e.preventDefault(); MarginOffset = parseInt(ScrollArea.style.marginTop.replace("px", "")); if (isNaN(MarginOffset)) { MarginOffset = 0; } StartY = e.touches[0].pageY ; StartX = e.touches[0].pageX; ScrollVerticalLock = false; ScrollHorizontalLock = false; var i; if (TouceArea.children.length > 0) { var liArea; var i; TouchedItem = null; TouchedOpen = false; for (i = 0; i < TouceArea.children[0].childNodes.length; i++) { liArea = TouceArea.children[0].childNodes[i]; if (liArea.offsetTop > StartY) { TouchedItem = TouceArea.children[0].childNodes[i - 1]; break; } } if (!TouchedItem) { if (liArea.offsetTop + liArea.clientHeight > StartY) { TouchedItem = TouceArea.children[0].childNodes[TouceArea.children[0].childNodes.length - 1]; } } }
}
TouceArea.ontouchmove = function(e) { e.preventDefault(); var OffsetY = e.touches[0].pageY - StartY; var OffsetX = e.touches[0].pageX - StartX - 20; if (ScrollHorizontalLock) { if (TouchedItem && OffsetX > 0) { TouchedItem.style.marginLeft = OffsetX + "px"; if (OffsetX > TouchedItem.clientWidth / 2) { TouchedItem.style.backgroundColor = "rgba(13,118,13,0.60)"; TouchedOpen = true; } else { TouchedItem.style.backgroundColor = ""; TouchedOpen = false; } } return; } var NewMargin = OffsetY + MarginOffset; if (TouceArea.clientHeight + NewMargin < WholeView.clientHeight * 0.7) { NewMargin = WholeView.clientHeight * 0.7 - TouceArea.clientHeight; } if (NewMargin > 0) NewMargin = 0; ScrollArea.style.marginTop = NewMargin + "px"; if (ScrollVerticalLock) { return; }
if (!TouchedItem) { ScrollVerticalLock = true; } else if (Math.abs(OffsetY) > 15) { ScrollVerticalLock = true; } else if (OffsetX > 0) { ScrollHorizontalLock = true; } }
TouceArea.ontouchend = function(e) { e.preventDefault(); if (TouchedItem) { TouchedItem.style.marginLeft = "0px"; TouchedItem.style.backgroundColor = ""; if (TouchedOpen) { hide(); window.setTimeout('window.location.href=' + '"' + TouchedItem.children[0].href + '"', 200); } } }
|
完整的mobile.js
文件在这里。
最终成品效果
实际使用下来还是比较满意的,搜索效果像这样: