一、click300ms延遲?
講道理,如今開發移動端基本是不會有這麼一個問題的。但做爲移動端之前的經典坑,我這裏也拿出來講上一說吧。
移動設備上的web網頁是有300ms延遲的,玩玩會形成按鈕點擊延遲甚至是點擊失效。這是因爲區分單擊事件和雙擊屏幕縮放的歷史緣由形成的。但在2014年的Chrome 32版本已經把這個延遲去掉了,so you know。但若是你仍是出現了300ms的延遲問題,也是有路子搞定的。css
解決方案以下:html
1.fastclick能夠解決在手機上點擊事件的300ms延遲前端
2.zepto的touch模塊,tap事件也是爲了解決在click的延遲問題vue
3.觸摸事件的響應順序爲 touchstart --> touchmove --> touchend --> click,也能夠經過綁定ontouchstart事件,加快對事件的響應,解決300ms延遲問題jquery
4.若移動設備兼容性正常的話(IE/Firefox/Safari(IOS 9.3)及以上),只需加上一個meta標籤android
<meta name="viewport" content="width=device-width">
二、移動端樣式兼容處理
當今的手機端,各式各樣的手機,屏幕分辨率也是各有不一樣,爲了讓頁面能夠能夠兼容各大手機,解決方案以下ios
1.設置meta標籤viewport屬性,使其無視設備的真實分辨率,直接經過dpi,在物理尺寸和瀏覽器之間重設分辨率,從而達到能有統一的分辨率的效果。而且禁止掉用戶縮放git
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
2.使用rem進行屏幕適配,設置好root元素的font-size大小,而後在開發的時候,全部與像素有關的佈局統一換成rem單位。針對不一樣的手機,使用媒體查詢對root元素font-size進行調整github
三、阻止旋轉屏幕時自動調整字體大小
移動端開發時,屏幕有豎屏和橫屏模式,當屏幕進行旋轉時,字體大小則有可能會發生變化,從而影響頁面佈局的總體樣式,爲避免此類狀況發生,只需設置以下樣式便可
-
-
-webkit-text-size-adjust: none;
-
四、修改移動端難看的點擊的高亮效果,iOS和安卓下都有效
-
-
-webkit-tap-highlight-color: rgba(
0,0,0,0);
-
五、iOS下取消input在輸入的時候英文首字母的默認大寫
<input type="text" autocapitalize="none">
六、禁止 iOS 識別長串數字爲電話
<meta name="format-detection" content="telephone=no" />
七、禁止 iOS 彈出各類操做窗口
-webkit-touch-callout: none;
八、禁止ios和android用戶選中文字
-webkit-user-select: none;
九、calc的兼容處理nainaitea.com
CSS3中的calc變量在iOS6瀏覽器中必須加-webkit-前綴,目前的FF瀏覽器已經無需-moz-前綴。 Android瀏覽器目前仍然不支持calc,因此要在以前增長一個保守尺寸:
-
-
-
width: -webkit-calc(
100% - 50px);
-
width: calc(
100% - 50px);
-
十、fixed定位缺陷
-
iOS下
fixed元素容易定位出錯,軟鍵盤彈出時,影響fixed元素定位,android下fixed表現要比iOS更好,軟鍵盤彈出時,不會影響fixed元素定位 。iOS4下不支持position:fixed
-
-
十一、一些狀況下對非可點擊元素如(label,span)監聽click事件,ios下不會觸發
針對此種狀況只須要對不觸發click事件的那些元素添加一行css代碼便可
十二、消除transition閃屏問題
-
-
-webkit-transform-style: preserve
-3d;
-
-
-webkit-backface-visibility: hidden;
1三、CSS動畫頁面閃白,動畫卡頓
解決方法:
1.儘量地使用合成屬性transform和opacity來設計CSS3動畫,不使用position的left和top來定位
2.開啓硬件加速
-
-webkit-transform: translate3d(
0, 0, 0);
-
-moz-transform: translate3d(
0, 0, 0);
-
-ms-transform: translate3d(
0, 0, 0);
-
transform: translate3d(
0, 0, 0);
1四、iOS系統中文輸入法輸入英文時,字母之間可能會出現一個六分之一的空格
解決方法:經過正則去除
this.value = this.value.replace(/\u2006/g, ‘‘);
1五、input的placeholder會出現文本位置偏上的狀況
input 的placeholder會出現文本位置偏上的狀況:PC端設置line-height等於height可以對齊,而移動端仍然是偏上,解決方案時是設置css
1六、浮動子元素撐開父元素盒子高度
解決方法以下:
- 父元素設置爲 overflow: hidden;
- 父元素設置爲 display: inline-block; 等
這裏兩種方法都是經過設置css屬性將浮動元素的父元素變成間接變成BFC元素,而後使得子元素高度能夠撐開父元素。這裏須要注意的時,最好使用方法1, 由於inline-block元素自己會自帶一些寬高度撐開其自己。
1七、往返緩存問題
點擊瀏覽器的回退,有時候不會自動執行js,特別是在mobilesafari中。這與往返緩存(bfcache)有關係。 解決方法 :
window.onunload = function () {};
1八、overflow-x: auto在iOS有兼容問題
解決方法:
-webkit-overflow-scrolling: touch;
2、vue移動開發特有坑以及小技巧分享
一、iOS原始輸入法問題
iOS原始輸入法,中文輸入時,沒法觸發keyup事件,且keyup.enter事件不管中英文,都沒法觸發
解決方法:
- 改用input事件進行監聽
- 將keyup監聽替換成值的watch
- 讓使用者安裝三方輸入法,好比搜狗輸入法(不太現實)
二、input元素失焦問題
業務場景重現: 項目中須要寫一個搜索組件,相關代碼以下
-
-
<div
class="y-search" :style="styles" :clear="clear">
-
<form action=
"#" onsubmit="return false;">
-
-
-
-
-
:placeholder=
"placeholder"
-
-
@keyup.enter=
"searchEnterFn"
-
-
-
-
<y-icons
class="search-icon" name="search" size="14"></y-icons>
-
-
<div v-
if="showClose" @click="closeFn">
-
<y-icons
class="close-icon" name=‘close‘ size=‘12‘></y-icons>
-
-
-
其中我須要在enter的時候進行對應的搜索操做並實現失焦,解決方法其實很簡單,在enter時進行DOM操做便可
-
-
document.getElementsByClassName(‘y-search-input‘)[
0].blur()
-
-
對了,這裏還有一個坑,就是在移動端使用input類型爲search的時候,必須使用form標籤包裹起來,這樣在移動端呼出鍵盤的enter纔會是搜索按鈕,不然只是默認的enter按鈕。
三、vue組件開發
這個點不能算坑,只能算是小技巧分享吧。
業務場景重現:不少時候,在開發項目的時候是須要抽離公共組件和業務組件的。而有些公共組件在全局註冊的同時可能還須要拓展成vue的實例方法,經過把它們添加到 Vue.prototype 上實現,方便直接使用js全局調用。拿一個Message組件作例子吧,代碼比較簡單,就直接上代碼了。
1.首先開發好Message.vue文件。
-
-
<div
class=‘y-mask-white-dialog‘ v-show=‘show‘>
-
<div
class=‘y-message animated zoomIn‘ >
-
<span v-html=
"msg"></span>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
<style lang=
"stylus" scoped>
-
-
outline: 0px; margin: 0px; padding: 0px; color: rgb(152, 104, 1); overflow-wrap: break-word;">0,
0, 0, .4);
-
-
-
-
-
-
-
-
-
-
-
-webkit-box-pack: center;
-
-webkit-justify-content: center;
-
-
-
-webkit-box-align: center;
-
-webkit-align-items: center;
-
-
-
-
-
-
-
-
-
-
-
-
background :rgba(
0,0,0,0.8);
-
-
animation: zoomIn
.15s ease forwards;
-
-
2.構建Message的Constructor
-
-
-
const MsgConstructor = Vue.extend(require(‘./Message.vue‘));
-
-
const instance = new MsgConstructor({
-
-
}).$mount(document.createElement(‘div‘));
-
-
MsgConstructor.prototype.closeMsg = function () {
-
-
el.parentNode && el.parentNode.removeChild(el);
-
typeof this.callback === ‘function‘ && this.callback();
-
-
-
const Message = (options = {}) => {
-
instance.msg = options.msg;
-
instance.timeout = options.timeout ||
2000;
-
instance.icon = options.icon;
-
instance.callback = options.callback;
-
document.body.appendChild(instance.$el);
-
-
const timer = setTimeout(() => {
-
-
-
}, instance.timeout +
100);
-
-
-
3.在main.js裏面進行組件註冊
-
import Message
from ‘./components/Message‘;
-
-
Vue.component(Message.name, Message)
-
Vue.prototype.$message = Message
而後你就能夠盡情使用Message組件了.
四、巧用flex佈局讓圖片等比縮放
這也是一個小技巧!項目中須要開發swiper輪播圖,那麼你懂的,圖片確定是須要保證等比縮放展現。
-
-
-
-
-
<style lang=
"stylus" scoped>
-
-
-
-
-
-
-
-
-
-
-
-
是否是賊簡單,是的,賊簡單。這個樣式同時適應手機全屏預覽豎屏的狀況,當手機橫屏的時候,加一個媒體查詢便可搞定
-
@media (orientation: landscape) {
-
-
-
-
-
-
五、枚舉值過濾處理
業務重現:考慮到項目後期會作國際化,前端須要對項目中幾乎全部的枚舉值進行過濾處理,從而進行展現
接下來就直接講講這塊吧。既然要過濾,那麼首選確定是vue提供的filter指令。這裏我舉一個支付方式的枚舉值處理的例子。首先配置代碼以下
-
-
-
env: (process.env.NODE_ENV === ‘development‘ ? require(‘./env/dev‘) : require(‘./env/pro‘)),
-
-
-
枚舉代碼以下
-
-
import config
from ‘../config/index‘;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
export
default type[lng];
枚舉註冊代碼分別以下
-
import accountType
from ‘./accountType‘;
-
-
-
-
-
-
-
return accountType[value] ? accountType[value] : ‘請選擇帳戶類型‘;
-
-
-
-
-
-
filter: function(
value, type, status) {
-
return factory[type](value, status);
-
-
-
-
-
-
-
-
import baseFilter
from ‘./filter/index‘;
-
-
-
-
-
-
Vue.filter(f.name, f.filter);
-
-
接下來就能夠輕鬆使用啦
-
-
-
-
{{info.account_type | formatEnum(‘accountType‘)}}
-
-
六、時間過濾處理
這點仍是屬於過濾處理的一個part,可是手機端有個兼容問題,若是是時間戳轉的話,那麼能夠轉化成任意咱們想要的形式,可是String類型的時間轉化的話,他只能兼容 "yyyy/MM/dd" 形式的時間值,由於咱們DateTime組件默認的形式是"yyyy-MM-dd",那麼只須要在DateTime組件正則替換一下便可,代碼以下
currentValue = _this.currentValue = _this.value ? _this.value.replace(/-/g, ‘/‘) : ‘‘;
時間過濾代碼以下
-
-
-
-
filter: function(
value, type, status) {
-
return factory[type](value, status);
-
-
-
-
-
filter: function(
value, format = ‘yyyy-MM-dd‘) {
-
if (!value || value === ‘‘) return ‘‘;
-
-
-
-
-
const newDate = new Date(v);
-
return newDate.Format(format);
-
-
-
七、路由權限斷定
業務重現:因爲不一樣的用戶,可能擁有不一樣權限,而目前咱們的項目是基於微信公衆號進行開發的,頁面權限這邊也是交給了咱們前端處理。既然要前端配置權限,那麼咱們能想到的比較好的方式就是經過配置路由文件,完成權限斷定。下面我會列舉一小部分代碼(以咱們的工單列表)進行演示,路由配置代碼以下
-
const getWorkOrder = pageName => resolve => require([‘../pages/WorkOrder‘], pages => resolve(pages[pageName]))
-
-
-
-
-
-
-
-
-
-
-
-
-
component: getWorkOrder(‘WorkOrderList‘)
-
-
-
-
-
-
component: getWorkOrder(‘ManagerWorkOrder‘)
-
-
-
-
而後進行路由統一過濾處理
-
-
import Store
from ‘store‘;
-
import Router
from ‘vue-router‘;
-
-
import routers
from ‘./router.config‘;
-
-
-
-
-
const routeName = function (router) {
-
if (!router) return false;
-
-
-
-
-
-
-
-
const RouterModel = new Router({
-
-
-
-
-
-
RouterModel.beforeEach((to,
from, next) => {
-
-
let qu = Object.entries(to.query);
-
-
qu = qu.map((item, index) => {
-
-
-
-
-
-
const userInfo = Store.get(‘yu_info‘);
-
const cookie = Vue.prototype.$util.getCookie(‘X-Auth-Token‘);
-
const userId = Vue.prototype.$util.getCookie(‘userid‘);
-
if (userInfo && cookie && +userId > 0) {
-
-
-
-
let param = `jumpUrl=${to.path}`;
-
-
param += `&${qu.
join("&")}`;
-
-
if (arr[to.name] && !to.query.rule) {
-
param += `&rule=${arr[to.name]}`;
-
-
window.location.href = `/login?${param}`;
-
-
-
-
-
-
-
-
export
default RouterModel;
而後在登錄界面定位到微信受權
-
-
-
-
let query = this.$route.query;
-
let param = `jumpUrl=${query.jumpUrl || ‘/home‘}`;
-
let path = window.location.origin;
-
-
let cfg = api[query.rule ? query.rule : 1];
-
-
param += `&rule=${query.rule}`;
-
-
-
let redirect_url = encodeURIComponent(`${path}/login?${param}`);
-
-
-
url += ‘&agentid=
1000004‘;
-
-
-
-
若是不是微信端,訪問到到rule規則的界面時,則會以下
而當微信受權經過的時候,rule權限不足的狀況則會以下
八、使用vue-cli proxyTable進行反向代理,解決跨域問題
開發項目,在先後端聯調的時候確定是會趕上跨域的問題的。很簡單,作個反向代理唄,對於想了解正向代理和反向代理的,請點擊這裏
vue-cli腳手架搭建的工程中,在config/index.js文件中能夠利用預留的proxyTable一項,設置地址映射表,以下
而後使用http-proxy-middleware插件對api請求地址進行代理
-
-
Object.keys(proxyTable).forEach(function (context) {
-
var options = proxyTable[context]
-
if (typeof options === ‘string‘) {
-
options = { target: options }
-
-
app.use(proxyMiddleware(options.filter || context, options))
-
http-proxy-middleware地址
3、移動端開發性能優化
一、首屏渲染優化
決定用戶體驗最重要的一個點之一,這個點的重要性,相信不用我說了。下面直接談實戰。
- 減小資源請求次數
- 加載時使用過渡樣式,防止用戶網絡太差影響對首頁的體驗
- 圖片使用懶加載,這一part,咱們目前項目中使用的vue的三方插件vue-lazyload,大體使用方法以下
-
-
-
-
error: require(‘./assets/close.svg‘),
-
loading: require(‘./assets/loading.svg‘),
-
-
-
-
-
<img v-lazy=
"room.img" :alt="room.community_name" width="100%">
- HTML使用Viewport,Viewport能夠加速頁面的渲染。
<meta name=」viewport」 content=」width=device-width, initial-scale=1″>
除此以外,還有不少點可作優化,進而提高首屏加載速度。
二、雪碧圖
這個老生常談了,爲了減小圖片請求次數,加快頁面加載,固然會考慮使用雪碧圖。儘可能使用::before或::after僞類,Sprites中的圖片排版能夠更緊 ,圖片體積更小, HTML更簡潔。
-
<style lang=
"stylus" scoped>
-
-
-
-
-
-
-
-
-
-
-
-
-
background: url(‘../../assets/sprite-min.png‘)
0px 0px no-repeat;
-
-
-
三、路由懶加載
關於路由懶加載這一部分,尤大在vue-router文檔中也有所說起,連接點擊這裏。
其實在vue項目中使用路由懶加載很是簡單,咱們要作的就是把路由對應的組件定義成異步組件,代碼以下
-
-
-
-
-
require.ensure([‘./Foo.vue‘], () => {
-
resolve(require(‘./Foo.vue‘))
-
-
-
-
const Foo = resolve => require([‘./Foo.vue‘], resolve)
再將組件按組分塊,如
const Foo = r => require.ensure([], () => r(require(‘./Foo.vue‘)), ‘group-foo‘)
實際項目中的代碼則如同我在章節《路由權限斷定》說起到的同樣
-
const getWorkOrder = pageName => resolve => require([‘../pages/WorkOrder‘], pages => resolve(pages[pageName]))
-
-
-
-
-
-
-
-
-
-
-
-
-
component: getWorkOrder(‘WorkOrderList‘)
-
-
-
-
-
-
component: getWorkOrder(‘ManagerWorkOrder‘)
-
-
-
-
如上將組件經過傳遞pageName參數分別打包到了各個chunk中,這樣每一個組件加載時都只會加載本身對應的代碼,從而加快渲染速度!
四、全局組件按需註冊
當時咱們爲了優化首屏渲染速度,也是考慮到這一點,項目的src/main.js文件主要負責註冊全局組件,插件,路由,以及實例化Vue等。在webpack的配置裏面也是當成entry入口進行了配置,若是我在main.js裏面講每一個組件都進行import的話,那麼它將會所有一塊兒註冊打包,頁面加載也會將每一個組件文件都加載下來,這樣對渲染速度仍是有必定影響的。
解決方法就是:按需註冊,這樣在打包的時候,會按需加載首頁(其餘界面也一樣適用)使用到的全局組件。基本步驟以下:
將須要註冊的組件寫進components/base.js文件中,而後exports出來
-
exports.Foo = require(‘./Foo.vue‘);
-
exports.Bar = require(‘./Bar.vue‘);
-
exports.Baz = require(‘./Baz.vue‘);
在main.js中進行註冊
-
-
require(‘./components/
base‘).Foo,
-
require(‘./components/
base‘).Bar,
-
require(‘./components/
base‘).Baz,
-
-
-
components.map(component => {
-
Vue.component(component.name, component);
-