由於公司項目須要,須要用vue作一個移動端版本;如今從0開始搭建,順便記下搭建過程,方便往後回顧;歡迎 你們指出不足。
先看設計稿:
在main.js 中寫下css
//全局組件 import topBar from '@/components/mobileTop.vue' Vue.component('topBar', topBar);
1,去定義阿里圖標,並引入html
2,設置 icon 組件,並寫html前端
3,由於vue 模板沒有引入 scss ,因此要本身安裝sass-loader,node-loadervue
cnpm i node-sass sass-loader -D
4,寫less,此佈局icon 使用 position 定位佈局node
因為後面加上 flexible-js 自適應 ,因此我們用 rem 佈局,參看下面的代碼,我們直接用實際尺寸除以100就能夠;ios
.content{ position: relative; padding:0 1.2rem 0 1.2rem; }
這個佈局在調試的時候徹底沒有問題;可是在真機調試的時候回存在問題,中間的 main 若是設置了移動端滾動 -webkit-overflow-scrolling:touch;會致使 滑動不了;可是若是不設置,就只能用插件去模擬滾動,很是很差;
而且 若是採用此方式,到了移動端會不時的拉起底部的bottom,讓人感受就是一個網頁css3
.box{ position: relative; height: 100%; } .top{ height: 1rem; background: red; position: absolute; top:0; left: 0; right: 0; z-index: 2; } .bot{ height: 1rem; background: red; position: absolute; bottom:0; left: 0; right: 0; z-index: 2; } .mid{ height: 100%; padding:1rem 0; width: 100%; overflow-y: auto; overflow-x: hidden; background: blue; box-sizing: border-box; }
這個結構能夠知足幾乎全部要求,可是仍是會有拉起底部的問題;web
採用此方式可能會有一些忽隱忽現的問題,可是最大的好處就是 頁面看起來徹底像移動頁面,底部也很差拉起來;滾動條至關於原生的滾動條,因此基本沒有bug;有個存在的問題在這個文章中提到 https://www.cnblogs.com/xiahj...;
目前我遇到的bug 在文章最後排除了。ajax
這個算是我比較看中的方式,由於效果基本跟原生同樣;npm
我試過用 better-scroll 處理滾動問題,可是由於微信端會有卡頓感,因此最後仍是放棄了;有需求的朋友,能夠根據本身狀況加入better-scroll方案;
<script> document.head.appendChild(meta); (function(doc, win){ var docE1 = doc.documentElement, resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize', recalc = function(){ var clientWidth = docE1.clientWidth; if(!clientWidth) return; //docE1.style.fontSize = clientWidth / 375 + 'px'; 這裏但願設置 1rem = 1px,實驗證實,這樣作 會致使 html 的 fontsize小於 12px docE1.style.fontSize = (clientWidth / 750)*100 + 'px'; //乘以100的意義是,1爲了避免受fontsize小於12的影響,2爲了計算方便; }; if (!doc.addEventListener) return; win.addEventListener(resizeEvt,recalc,false); doc.addEventListener('DOMContentLoaded',recalc,false); })(document,window); </script>
//引入公共樣式 import '@/common/reset.css' import '@/common/common.css'
/* * @Author lizhenhua * @version 2018/5/17 * @description */ import axios from 'axios' import store from '../store' import {Message} from 'element-ui' import {getToken,removeToken} from '@/util/cookie' import tools from '@/util/tools' import qs from 'qs' // 建立axios實例 const service = axios.create({ baseURL: process.env.BASE_API, // api的base_url timeout: 1000 // 請求超時時間 }) // request攔截器 service.interceptors.request.use(config => { //若是是開發環境,爲非模擬接口加上「跨域」前綴 'ln' if(process.env.NODE_ENV=='development'&& config.url.indexOf('api')==-1){ config.url = 'ln/'+ config.url; } let token = getToken(); //若是data參數爲 對象或者數組,就把參數 封裝到key爲data 屬性中; if(typeof config.data == "object" ||typeof config.data == "Object" ||typeof config.data == "OBJECT"){ let data = tools.cloneObj(config.data); config.data = {}; config.data['data'] = JSON.stringify(data); }else { config.data = {}; } //統一爲全部請求加上 這兩個參數 if (token) { config.data['LE_AUTH_TOKEN'] = token config.data['token'] = token } //設置頭部token if (store.getters.token) { config.headers['X-Token'] = token // 讓每一個請求攜帶自定義token 請根據實際狀況自行修改 } //不設置 這樣,後臺拿不到數據 config.headers['Content-Type'] = 'application/x-www-form-urlencoded' //get請求,只能放在 params 中,轉爲url傳參的方式 //因此統一使用post請求,只有post存在 paramBody,咱們能夠吧參數放在 data 中 config.method = "POST" //把全部參數處理爲 form 表單提交的方式,而且轉義,若是不這樣,後端(會直接獲得字符串,不是正常對象)解析不出來; //前端發送:data=%7B%22loginName%22%3A%22lzh%22%2C%22loginPassword%22%3A%22123456%22%2C%22appId%22%3A%22lext79987422-5180-40%22%2C%22platType%22%3A1%7D //後端收到:{data={"loginName":"lzh","loginPassword":"123456","appId":"lext79987422-5180-40","platType":1}} config.data = qs.stringify(config.data) return config }, error => { // Do something with request error console.log(error) // for debug Promise.reject(error) }) // respone攔截器 service.interceptors.response.use( response => { let res = response.data; if (res.status == 1) { return res.data }if(res.status ==-1208){ Message({ message: res.errorMsg, type: 'error', duration: 5 * 1000 }) removeToken(); } else { //這裏處理 全部數據錯誤 Message({ message: res.errorMsg, type: 'error', duration: 5 * 1000 }) return Promise.reject(res.errorMsg) } }, error => { //這裏處理的是 全部網絡請求錯誤 console.log('err' + error)// for debug let err = error + '', info = ''; if (err.indexOf('timeout') != -1) { info = "請求超時"; } else { info = err } Message({ message: info, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } ) export default service
能夠根據本身狀況,攔截 ajax 後做統一處理;
把http.js 在main.js 中 引入
//引入 axios 實例 import $http from '@/util/$http' Vue.prototype.$http = $http;
<script> export default { data: function () { return { document: {} } }, created() { this.$http({ url: this.ajaxApi.test.list, data: { id: "docid:6CFE06297BBA4E1FBAA00BDE2809198F" }, }).then(res => { if(res){ this.document = this.tools.cloneObj(res.document) } }) } } </script>
// api 表 export default { test: { list:"/api/data/document" } } //引入 api 表 import ajaxApi from "@/util/ajaxApi" Vue.prototype.ajaxApi = ajaxApi
// tools.js export default { cloneObj (obj){ var str, newobj = obj.constructor === Array ? [] : {}; if (typeof obj !== 'object') { return; } else if (window.JSON) { str = JSON.stringify(obj), //序列化對象 newobj = JSON.parse(str); //還原 } else { for (var i in obj) { newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i]; } } return newobj; } } //引入工具庫 import tools from "@/util/tools" Vue.prototype.tools = tools;
import Cookies from 'js-cookie' const TokenKey = 'LtpaToken2' export function getToken() { return Cookies.get(TokenKey) } export function setToken(token,time) { return Cookies.set(TokenKey, token,{expiry:time}) } export function removeToken() { return Cookies.remove(TokenKey) }
由於localhost 是不具備 局域網 訪問性的,因此咱們要改一下 項目的配置
在 config/index.js 找到以下代碼:
// host: 'localhost', // can be overwritten by process.env.HOST host: '10.20.139.118', // can be overwritten by process.env.HOST port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
改成你的ip 之後,重啓項目
在手機瀏覽器輸入 http://10.20.139.118:8080/#/ 就能夠訪問到你的頁面了
剛剛開始 開發的時候,開發出來的頁面 在webview上 滑動老是卡卡的感受,人家的頁面是絲質順滑,跟原生的同樣;後來想到了 用一個插件
模擬這種效果,iscroll.js;
其實 只須要一句css 就能解決這個緩動的效果
在 app.vue 下寫
html, body { -webkit-overflow-scrolling: touch; }
MDN上是這樣定義的:
-webkit-overflow-scrolling 屬性控制元素在移動設備上是否使用滾動回彈效果. auto: 使用普通滾動, 當手指從觸摸屏上移開,滾動會當即中止。 touch: 使用具備回彈效果的滾動,
當手指從觸摸屏上移開,內容會繼續保持一段時間的滾動效果。繼續滾動的速度和持續的時間和滾動手勢的強烈程度成正比。同時也會建立一個新的堆棧上下文。
咱們一般會在移動端佈局中接觸到 流程進度列表 結構的設計圖;例如淘寶的:物流進度圖;此次拿到的設計稿是這樣:
這兩個結構能夠看作同樣的;總體分爲左(標籤)中(長線和點)右(內容)三部分,其中,最左邊考慮到它位置直接貼在邊上,一定是用絕對定位實現;最右邊是普通的佈局,難點在於怎麼處理中間這根貫穿整個列表的線,和上面的圓點。
目前我知道的有兩種方法:
一個是每一個li 中用div畫出本身的線和點,而後每一個線拼接起來組成長線,這個方法的缺點是比較難定線的長度,想用height:100%,可是不生效,極可能要用到js;
第二種是本次我採用的方法,用li的僞元素before畫線,after 畫圓點,經過z-index設置覆蓋層級;這樣的好處是,線的高度能夠用height:100%;難點是圓點在不一樣分辨率下,可能會出現偏移的狀況(線沒有穿過圓心);這裏直接給圓點作了css3的居中定位,並用magin-right的負值微調了一下,初步測試在不一樣分辨率下表現都比較好;在這裏給出實現代碼:
<ul class="item-ul"> <li class="flex-bet"> <div class="list-left">擬稿意見</div> <div class="list-right"> <div class="top flex-bet"> <div class="top-left"><span class="yl">公偉傑</span>信息技術部</div> <div class="date">2018-07-12</div> </div> <p>這個提議不錯,試試看</p> </div> </li> //如下重複這個li </ul>
/*流程表*/ .flex-bet{ display: flex; justify-content: space-between; align-items: center; } .item-ul { padding: 0.2rem 0; li { position: relative; padding-left: 1.2rem; padding-bottom: 0.2rem; &:before { content: ""; position: absolute; left: 1rem; top: 8px; width: 1px; background: #58a8ff; height: 100%; } &:after { content: ""; position: absolute; left: 0.945rem; top: 8px; width: 0.1rem; height: 0.1rem; border: 1px solid #57a9ff; border-radius: 50%; background: #fff; margin-right: -2px; } .list-left { position: absolute; width: 1.4rem; height: 0.57rem; line-height: 0.57rem; font-size: 12px; text-align: center; color: #fff; background: #58a8ff; border-radius: 0 0.7rem 0.7rem 0; left: 0; top: 0; z-index: 5; } .list-mid { align-self: start; z-index: 4; height: 100%; text-align: center; width: 20px; margin-top: -4px; .icon { display: inline-block; width: 0.1rem; height: 0.1rem; border: 1px solid #57a9ff; border-radius: 50%; background: #fff; margin-right: -2px; } } .list-right { width: 6.1rem; padding: 0.05rem 0.3rem 0 0.5rem; font-size: 12px; .top-left { color: #8c8c8c; span { display: inline-block; padding: 0.05rem 0.2rem; color: #484848; border-radius: 15px; margin-right: 0.2rem; background: transparent; font-size: 15px; } .yl { background: #ffedd9; } .bl { background: #daecff; } .pin { background: #ffe0eb; } .zl { background: #e3e0ff; } } .date { color: #8c8c8c; } p { text-align: left; font-size: 12px; color: #484848; line-height: 0.57rem; padding-left: 4px; } .keyword { text-align: left; margin-top: 0.1rem; span { display: inline-block; width: 1rem; height: 0.35rem; line-height: 0.35rem; text-align: center; font-size: 12px; border: 1px solid #b3b3b3; margin-right: 0.15rem; &:first-child { border: 1px solid #57a9fb; color: #57a9fb; } } } } } li:last-child:before { height: 0.1rem; } }
需求常見: 點擊某個input,劃開一個新頁面,裏面能夠填300字意見;我watch show/hide 變量,若是顯示狀態的話,就讓子組件的textarea focus;這個時候,這個時候就出現了光標在中間的狀況;
解決方案是設置100 毫秒的延遲
watch:{ control(val){ if(val){ /*延遲100毫秒,fix 光標定位在中間的bug*/ setTimeout(()=>{ this.$refs.textBox.focus(); },100) } } }
解決方案是當彈窗的時候,給發生滾動的盒子 加上 overflow:hide;關閉彈窗的時候移除;
你還能夠open的時候記住滾動條的位置,close的時候復原;
這裏最大的坑多是,要找清楚真實發生了滾動的盒子;極可能不是body;
.oh{ overflow:hidden !important; } openPop(value){ this[value] = true; document.getElementById('app').className ='oh' }, closePop(value){ this[value] = false; document.getElementById('app').className=' '; }
html, body{ position: relative; height: 100%; -webkit-overflow-scrolling: touch; //多是跟這個屬性衝突了 /*overflow-y: auto;*/ /*overflow-x: hidden;*/ /*這裏不能加overflow全部屬性,在蘋果下會有上下拉蓋住頂部底部的bug */ }
傳統的作法是用 百分比定高,可是要一層層設置 父元素的高度。否則百分比獲取不到值。因此這裏建議用 vh 代替 %
最後的解決方案是經過定位 把輸入部分上提
詳細的討論在下面作了筆記
https://segmentfault.com/n/13...