1. 程式人生 > >移動端開發常見的坑

移動端開發常見的坑

filters navigator oar com [] 註意 amp use node

一、移動端開發通用坑

1、click300ms延遲?

講道理,現在開發移動端基本是不會有這麽一個問題的。但作為移動端以前的經典坑,我這裏也拿出來說上一說吧。
移動設備上的web網頁是有300ms延遲的,玩玩會造成按鈕點擊延遲甚至是點擊失效。這是由於區分單擊事件和雙擊屏幕縮放的歷史原因造成的。但在2014年的Chrome 32版本已經把這個延遲去掉了,so you know。但如果你還是出現了300ms的延遲問題,也是有路子搞定的。

解決方案如下:

1.fastclick可以解決在手機上點擊事件的300ms延遲

2.zepto的touch模塊,tap事件也是為了解決在click的延遲問題

3.觸摸事件的響應順序為 touchstart --> touchmove --> touchend --> click,也可以通過綁定ontouchstart事件,加快對事件的響應,解決300ms延遲問題

4.若移動設備兼容性正常的話(IE/Firefox/Safari(IOS 9.3)及以上),只需加上一個meta標簽

<meta name="viewport" content="width=device-width">

即把viewport設置成設備的實際像素,那麽就不會有這300ms的延遲。

2、移動端樣式兼容處理

當今的手機端,各式各樣的手機,屏幕分辨率也是各有不同,為了讓頁面可以可以兼容各大手機,解決方案如下

1.設置meta標簽viewport屬性,使其無視設備的真實分辨率,直接通過dpi,在物理尺寸和瀏覽器之間重設分辨率,從而達到能有統一的分辨率的效果。並且禁止掉用戶縮放

<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進行調整

3、阻止旋轉屏幕時自動調整字體大小

移動端開發時,屏幕有豎屏和橫屏模式,當屏幕進行旋轉時,字體大小則有可能會發生變化,從而影響頁面布局的整體樣式,為避免此類情況發生,只需設置如下樣式即可

* {
  -webkit-text-size-adjust: none;
}

4、修改移動端難看的點擊的高亮效果,iOS和安卓下都有效

* {
  -webkit-tap-highlight-color: rgba(0,0,0,0);
}

不過這個方法在現在的安卓瀏覽器下,只能去掉那個橙色的背景色,點擊產生的高亮邊框還是沒有去掉,有待解決!

一個CSS3的屬性,加上後,所關聯的元素的事件監聽都會失效,等於讓元素變得“看得見,點不著”。IE到11才開始支持,其他瀏覽器的當前版本基本都支持。詳細介紹見這

pointer-events: none;

5、iOS下取消input在輸入的時候英文首字母的默認大寫

<input type="text" autocapitalize="none">

6、禁止 iOS 識別長串數字為電話

<meta name="format-detection" content="telephone=no" />

7、禁止 iOS 彈出各種操作窗口

-webkit-touch-callout: none;

8、禁止ios和android用戶選中文字

-webkit-user-select: none;

9、calc的兼容處理

CSS3中的calc變量在iOS6瀏覽器中必須加-webkit-前綴,目前的FF瀏覽器已經無需-moz-前綴。 Android瀏覽器目前仍然不支持calc,所以要在之前增加一個保守尺寸:

div { 
  width: 95%; 
  width: -webkit-calc(100% - 50px); 
  width: calc(100% - 50px); 
}

10、fixed定位缺陷

iOS下fixed元素容易定位出錯,軟鍵盤彈出時,影響fixed元素定位,android下fixed表現要比iOS更好,軟鍵盤彈出時,不會影響fixed元素定位 。iOS4下不支持position:fixed

解決方案: 可用iScroll插件解決這個問題

11、一些情況下對非可點擊元素如(label,span)監聽click事件,ios下不會觸發

針對此種情況只需要對不觸發click事件的那些元素添加一行css代碼即可

cursor: pointer;

12、消除transition閃屏問題

/*設置內嵌的元素在 3D 空間如何呈現:保留 3D*/
-webkit-transform-style: preserve-3d;
/*(設置進行轉換的元素的背面在面對用戶時是否可見:隱藏)*/ 
-webkit-backface-visibility: hidden;

13、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);

14、iOS系統中文輸入法輸入英文時,字母之間可能會出現一個六分之一的空格

解決方法:通過正則去除

this.value = this.value.replace(/\u2006/g, ‘‘);

15、input的placeholder會出現文本位置偏上的情況

input 的placeholder會出現文本位置偏上的情況:PC端設置line-height等於height能夠對齊,而移動端仍然是偏上,解決方案時是設置css

line-height:normal;

16、浮動子元素撐開父元素盒子高度

解決方法如下:

  1. 父元素設置為 overflow: hidden;
  2. 父元素設置為 display: inline-block; 等

這裏兩種方法都是通過設置css屬性將浮動元素的父元素變成間接變成BFC元素,然後使得子元素高度可以撐開父元素。這裏需要註意的時,最好使用方法1, 因為inline-block元素本身會自帶一些寬高度撐開其本身。

17、往返緩存問題

點擊瀏覽器的回退,有時候不會自動執行js,特別是在mobilesafari中。這與往返緩存(bfcache)有關系。 解決方法 :

window.onunload = function () {};

18、overflow-x: auto在iOS有兼容問題

解決方法:

-webkit-overflow-scrolling: touch;

  

二、vue移動開發特有坑以及小技巧分享

1、iOS原始輸入法問題

iOS原始輸入法,中文輸入時,無法觸發keyup事件,且keyup.enter事件無論中英文,都無法觸發

解決方法:

  1. 改用input事件進行監聽
  2. 將keyup監聽替換成值的watch
  3. 讓使用者安裝三方輸入法,比如搜狗輸入法(不太現實)

2、input元素失焦問題

業務場景重現: 項目中需要寫一個搜索組件,相關代碼如下

<template>
  <div class="y-search" :style="styles" :clear="clear">
    <form action="#" onsubmit="return false;">
      <input type="search"
        class="y-search-input"
        ref="search"
        v-model=‘model‘
        :placeholder="placeholder"
        @input="searchInputFn"
        @keyup.enter="searchEnterFn"
        @foucs="searchFocusFn"
        @blur="searchBlurFn"
      />
      <y-icons class="search-icon" name="search" size="14"></y-icons>
    </form>
    <div v-if="showClose" @click="closeFn">
      <y-icons class="close-icon" name=‘close‘ size=‘12‘></y-icons>
    </div>
  </div>
</template>

其中我需要在enter的時候進行對應的搜索操作並實現失焦,解決方法其實很簡單,在enter時進行DOM操作即可

searchEnterFn (e) {
  document.getElementsByClassName(‘y-search-input‘)[0].blur()
  // dosomething yourself
}

  

對了,這裏還有一個坑,就是在移動端使用input類型為search的時候,必須使用form標簽包裹起來,這樣在移動端呼出鍵盤的enter才會是搜索按鈕,否則只是默認的enter按鈕。

3、vue組件開發

這個點不能算坑,只能算是小技巧分享吧。

業務場景重現:很多時候,在開發項目的時候是需要抽離公共組件和業務組件的。而有些公共組件在全局註冊的同時可能還需要拓展成vue的實例方法,通過把它們添加到 Vue.prototype 上實現,方便直接使用js全局調用。拿一個Message組件做例子吧,代碼比較簡單,就直接上代碼了。

1.首先開發好Message.vue文件。

<template>
  <div class=‘y-mask-white-dialog‘ v-show=‘show‘>
    <div class=‘y-message  animated zoomIn‘ >
      <span v-html="msg"></span>
    </div>
  </div>
</template>

<script>
export default {
  name: ‘yMessage‘,
  props: {
    msg: String,
    timeout: Number,
    callback: Function,
    icon: String,
  },
  data() {
    return {
      show: true,
    };
  }
};
</script>

<style lang="stylus"  scoped>
.y-mask-white-dialog {
  background-color: rgba(0, 0, 0, .4);
  position: fixed;
  z-index: 999;
  bottom: 0;
  right: 0;
  left: 0;
  top: 0;
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-box-align: center;
  -webkit-align-items: center;
  -ms-flex-align: center;
  align-items: center;
}
.y-message {
  min-width: 2.9rem;
  max-width: 5.5rem;
  width:100%;
  padding: 0.32rem;
  font-size: 14px;
  text-align: center;
  border-radius: 4px;
  background :rgba(0,0,0,0.8);
  color: #fff;
  animation: zoomIn .15s ease forwards;
}
</style>

2.構建Message的Constructor

import Vue from ‘vue‘;

const MsgConstructor = Vue.extend(require(‘./Message.vue‘));

const instance = new MsgConstructor({
  // el: document.createElement(‘div‘),
}).$mount(document.createElement(‘div‘));

MsgConstructor.prototype.closeMsg = function () {
  const el = instance.$el;
  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(() => {
    clearTimeout(timer);
    instance.closeMsg();
  }, instance.timeout + 100);
};

export default Message;

3.在main.js裏面進行組件註冊

import Message from ‘./components/Message‘;

Vue.component(Message.name, Message)
Vue.prototype.$message = Message

然後你就可以盡情使用Message組件了.

this.$message({
  msg: ‘test message‘
  // ...
})

4、巧用flex布局讓圖片等比縮放

這也是一個小技巧!項目中需要開發swiper輪播圖,那麽你懂的,圖片肯定是需要保證等比縮放展示。

<div class="parent">
  <img :src="imgSrc" >
</div>

<style lang="stylus" scoped>
.parent {
  width: 100px;
  height: 100px;
  display: flex;
  align-items: center;
  
  img {
    width :100%;
    height: auto;
  }
}
</style>

是不是賊簡單,是的,賊簡單。這個樣式同時適應手機全屏預覽豎屏的情況,當手機橫屏的時候,加一個媒體查詢即可搞定

@media (orientation: landscape) {
  img {
    width auto
    height 100%
    margin auto
  }
}

  

5、枚舉值過濾處理

業務重現:考慮到項目後期會做國際化,前端需要對項目中幾乎所有的枚舉值進行過濾處理,從而進行展示

接下來就直接講講這塊吧。既然要過濾,那麽首選肯定是vue提供的filter指令。這裏我舉一個支付方式的枚舉值處理的例子。首先配置代碼如下

// 配置文件
export default {
  env: (process.env.NODE_ENV === ‘development‘ ? require(‘./env/dev‘) : require(‘./env/pro‘)),
  headShow: false,
  lng: ‘zh‘,
};

 枚舉代碼如下

// 獲取語言環境
import config from ‘../config/index‘;

const {lng} = config;
// 賬戶類型
const type = {
  zh: {
    1: ‘銀行‘,
    2: ‘支付寶‘,
    3: ‘微信支付‘,
  },
  en: {
    1: ‘bank_type‘,
    2: ‘alipay_type‘,
    3: ‘wxpay_type‘,
  }
}
export default type[lng];

枚舉註冊代碼分別如下

import accountType from ‘./accountType‘; // 賬戶類型

const factory = {
  accountType(value) {
    if (value === -1) {
      return ‘請選擇賬戶類型‘;
    }
    return accountType[value] ? accountType[value] : ‘請選擇賬戶類型‘;
  }
}
const filter = [
  {
    name: ‘formatEnum‘, // 過濾類型
    filter: function(value, type, status) {
      return factory[type](value, status);
    }
  }
];
export default {
  filter
};
// filter
import baseFilter from ‘./filter/index‘;

const filters = [
  ...baseFilter.filter
];
filters.map(f => {
  Vue.filter(f.name, f.filter);
  return ‘‘;
});

接下來就可以輕松使用啦

<li>
  <label支付類型</label>
  <span>
    {{info.account_type | formatEnum(‘accountType‘)}}
  </span>
</li>

6、時間過濾處理

這點還是屬於過濾處理的一個part,但是手機端有個兼容問題,如果是時間戳轉的話,那麽可以轉化成任意我們想要的形式,但是String類型的時間轉化的話,他只能兼容 "yyyy/MM/dd" 形式的時間值,因為我們DateTime組件默認的形式是"yyyy-MM-dd",那麽只需要在DateTime組件正則替換一下即可,代碼如下
currentValue = _this.currentValue = _this.value ? _this.value.replace(/-/g, ‘/‘) : ‘‘;

時間過濾代碼如下

const filter = [
  {
    name: ‘formatEnum‘, // 過濾類型
    filter: function(value, type, status) {
      return factory[type](value, status);
    }
  },
  {
    name: ‘formatDate‘, // 日期
    filter: function(value, format = ‘yyyy-MM-dd‘) {
      if (!value || value === ‘‘) return ‘‘;
      let v = value;
      if (!isNaN(value)) {
        v = +value * 1000;
      }
      const newDate = new Date(v);
      return newDate.Format(format);
    },
  }
];

  

7、路由權限判定

業務重現:由於不同的用戶,可能擁有不同權限,而目前我們的項目是基於微信公眾號進行開發的,頁面權限這邊也是交給了我們前端處理。既然要前端配置權限,那麽我們能想到的比較好的方式就是通過配置路由文件,完成權限判定。下面我會列舉一小部分代碼(以我們的工單列表)進行演示,路由配置代碼如下

const getWorkOrder = pageName => resolve => require([‘../pages/WorkOrder‘], pages => resolve(pages[pageName]))

let routers = [];
routers = [
  {
    path: ‘/workorder‘,
    name: ‘workorder‘,
    component: room,
    children: [
      {
        path: ‘list‘, // 管家端工單列表
        name: ‘list‘,
        rule: 3,
        component: getWorkOrder(‘WorkOrderList‘) //WorkOrder,
      },
      {
        path: ‘managerList‘, // 店長端工單列表
        name: ‘managerList‘,
        rule: 6,
        component: getWorkOrder(‘ManagerWorkOrder‘) // WorkOrder,
      },
    ]
  }
]

然後進行路由統一過濾處理

import Vue from ‘vue‘;
import Store from ‘store‘;
import Router from ‘vue-router‘;

import routers from ‘./router.config‘;
Vue.use(Router);

// 遍歷路由名稱以及權限
let arr = {};
const routeName = function (router) {
  if (!router) return false;
  router.forEach((v) => {
    arr[v.name] = v.rule;
    routeName(v.children);
  })
}
routeName(routers);

const RouterModel = new Router({
  mode: ‘history‘,
  routes: routers,
});

// 路由鉤子,進入路由之前判斷
RouterModel.beforeEach((to, from, next) => {
  // 處理query 參數,傳入到 jumpUrl,便於登錄後跳轉到對應頁面
  let qu =  Object.entries(to.query);
  if (qu.length > 0) {
    qu = qu.map((item, index) => {
      return item.join(‘=‘);
    })
  }
  if (arr[to.name]) {
    // 如果有權限需要
    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) {
      next();
    } else {
      // 未登錄,跳轉登錄
      let param = `jumpUrl=${to.path}`;
      if (qu.length > 0) {
        param += `&${qu.join("&")}`;
      }
      if (arr[to.name] && !to.query.rule) {
        param += `&rule=${arr[to.name]}`;
      }
      window.location.href = `/login?${param}`;
    }
  } else {
    // 如果不需要權限放行
    next();
  }
})

export default RouterModel;

然後在登陸界面定位到微信授權


getCode() {
  // 定位到微信授權,若是不需要授權可以在此處處理
  let query = this.$route.query;
  let param = `jumpUrl=${query.jumpUrl || ‘/home‘}`;
  let path = window.location.origin;
  // 登錄角色處理
  let cfg = api[query.rule ? query.rule : 1];
  if (query.rule) {
    param += `&rule=${query.rule}`;
  }

  let redirect_url = encodeURIComponent(`${path}/login?${param}`);
  let url =  `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${cfg.tempApp}&redirect_uri=${redirect_url}&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect`;
  if (query.rule === 3) {
    url += ‘&agentid=1000004‘;
  }
  location.replace = url;
}

如果不是微信端,訪問到到rule規則的界面時,則會如下

技術分享

而當微信授權通過的時候,rule權限不足的情況則會如下

技術分享

8、使用vue-cli proxyTable進行反向代理,解決跨域問題

開發項目,在前後端聯調的時候肯定是會遇上跨域的問題的。很簡單,做個反向代理唄,對於想了解正向代理和反向代理的,請點擊這裏

vue-cli腳手架搭建的工程中,在config/index.js文件中可以利用預留的proxyTable一項,設置地址映射表,如下

proxyTable: {
  ‘/api‘: {
    target: ‘http://www.example.com‘, // your target host
    changeOrigin: true, // needed for virtual hosted sites
    pathRewrite: {
      ‘^/api‘: ‘‘  // rewrite path
    }
  }
}

然後使用http-proxy-middleware插件對api請求地址進行代理

// proxy api requests
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地址

三、移動端開發性能優化

技術分享

1、首屏渲染優化

決定用戶體驗最重要的一個點之一,這個點的重要性,相信不用我說了。下面直接談實戰。

  • 減少資源請求次數
  • 加載時使用過渡樣式,防止用戶網絡太差影響對首頁的體驗
  • 圖片使用懶加載,這一part,我們目前項目中使用的vue的三方插件vue-lazyload,大致使用方法如下
// 全局註冊 import VueLazyload from ‘vue-lazyload‘;

Vue.use(VueLazyload, {
  error: require(‘./assets/close.svg‘),
  loading: require(‘./assets/loading.svg‘),
  attempt: 1,
});

// 使用
<img v-lazy="room.img" :alt="room.community_name" width="100%">
  • HTML使用Viewport,Viewport可以加速頁面的渲染。
    <meta name=”viewport” content=”width=device-width, initial-scale=1″>

除此之外,還有很多點可做優化,進而提升首屏加載速度。

2、雪碧圖

這個老生常談了,為了減少圖片請求次數,加快頁面加載,當然會考慮使用雪碧圖。盡量使用::before或::after偽類,Sprites中的圖片排版可以更緊 ,圖片體積更小, HTML更簡潔。

<style lang="stylus" scoped>
  .chose-house {
    height: 86px;
    width: 64px;
    margin 0 auto
    position relative
    &::before {
      content: ‘\20‘;
      height: 100%;
      width: 100%;
      position: absolute;
      left: 0;
      top: 0;
      background: url(‘../../assets/sprite-min.png‘) 0px 0px no-repeat;
    }
  }
</style>

3、路由懶加載

關於路由懶加載這一部分,尤大在vue-router文檔中也有所提及,鏈接點擊這裏。

其實在vue項目中使用路由懶加載非常簡單,我們要做的就是把路由對應的組件定義成異步組件,代碼如下

//在router/index.js中引入組件時可使用如下異步方式引入
const Foo = resolve => {
  // require.ensure 是 Webpack 的特殊語法,用來設置 code-split point
  // (代碼分塊)
  require.ensure([‘./Foo.vue‘], () => {
    resolve(require(‘./Foo.vue‘))
  })
}
// or
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]))

let routers = [];
routers = [
  {
    path: ‘/workorder‘,
    name: ‘workorder‘,
    component: room,
    children: [
      {
        path: ‘list‘, // 管家端工單列表
        name: ‘list‘,
        rule: 3,
        component: getWorkOrder(‘WorkOrderList‘) //WorkOrder,
      },
      {
        path: ‘managerList‘, // 店長端工單列表
        name: ‘managerList‘,
        rule: 6,
        component: getWorkOrder(‘ManagerWorkOrder‘) // WorkOrder,
      },
    ]
  }
]

如上將組件通過傳遞pageName參數分別打包到了各個chunk中,這樣每個組件加載時都只會加載自己對應的代碼,從而加快渲染速度!

4、全局組件按需註冊

當時我們為了優化首屏渲染速度,也是考慮到這一點,項目的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中進行註冊

const components = [
  require(‘./components/base‘).Foo,
  require(‘./components/base‘).Bar,
  require(‘./components/base‘).Baz,
];

components.map(component => {
  Vue.component(component.name, component);
});

  



hybird應用開發的坑:

1:ios狀態欄與頁面內容重疊(webview中),如果是在微信端的網頁,可以忽略這個坑。

解決方法:判斷設備類型,如果是ios則加入獨有的樣式:一般狀態欄的高度是20px

var u = navigator.userAgent, app = navigator.appVersion;
var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios終端
if(isiOS){
	$("body").addClass("uh_ios7");
}

樣式文件下加這段:

.uh_ios7 .uh,.uh_ios7{
    padding: 20px 0 0;
}

3:當頁面輸入框獲取焦點的時候,ios頁面滾動導致頭部與狀態欄重疊:

首先我們下載插件: 傳送門

cordova plugin add ionic-plugin-keyboard.

然後在app.js中加入代碼:

$ionicPlatform.ready(function () {
          if (window.cordova && window.cordova.plugins.Keyboard) {
            window.cordova.plugins.Keyboard.hideKeyboardAccessoryBar(false);
            if (window.ionic.Platform.isIOS()) {
              window.cordova.plugins.Keyboard.disableScroll(true);
            }
          }
});

註意:在ios上$ionicPlatform.ready可能進不去————解決辦法就是:

將cordova.js放在頁面最底部引入!!!!fuck!!

4:ios上如何讓絕對定位在頁面底部的輸入框,隨鍵盤的出現而上移(僅限網頁)?

利用dom方法:scrollintoView()。

如果滾動頁面也是DOM沒有解決的一個問題。為了解決這個問題,瀏覽器實現了一下方法,以方便開發人員如何更好的控制頁面的滾動。在各種專有方法中,HTML5選擇了scrollIntoView()作為標準方法。scrollIntoView()可以在所有的HTML元素上調用,通過滾動瀏覽器窗口或某個容器元素,調用元素就可以出現在視窗中。如果給該方法傳入true作為參數,或者不傳入任何參數,那麽窗口滾動之後會讓調動元素頂部和視窗頂部盡可能齊平。如果傳入false作為參數,調用元素會盡可能全部出現在視口中(可能的話,調用元素的底部會與視口的頂部齊平。)不過頂部不一定齊平.

例子:document.querySelector(".pinlun_input").scrollIntoView(false) //這是js方法,不要用jquery選擇器執行此方法

移動端開發常見的坑