當拿到設計師給的UI設計圖,前端的首要任務就是佈局和樣式,相信這對於大部分前端工程師來講已經不是什麼難題了。移動端的佈局相對PC較爲簡單,關鍵在於對不一樣設備的適配。以前介紹了一篇關於移動端rem佈局方案,這大體是網易H5的適配方案。不過實踐中發現淘寶開源的可伸縮佈局方案效果更好且更容易使用。css
網易雲的方案總結爲:根據屏幕大小 / 750 = 所求字體 / 基準字體大小比值相等,動態調節html的font-size大小。html
淘寶的方案總結爲:根據設備設備像素比設置scale的值,保持視口device-width始終等於設備物理像素,接着根據屏幕大小動態計算根字體大小,具體是將屏幕劃分爲10等分,每份爲a,1rem就等於10a。前端
一般咱們會拿到750寬的設計稿,這是基於iPhone6的物理分辨率。有的設計師也許會偷懶,設計圖上面沒有任何的標註,若是咱們邊開發邊量尺寸,無疑效率是比較低的。要麼讓設計師標註上,要麼自食其力。若是設計師實在沒有時間,推薦使用markman進行標註,免費版閹割了一些功能(好比沒法保存本地)不過基本知足了咱們的需求了。vue
標註完成後開始寫咱們的樣式,使用了淘寶的lib-flexible庫以後,咱們的根字體基準值就爲750/100*10 = 75px。此時咱們從圖中若某個標註爲100px,那麼css中就應該設置爲100/75 = 1.333333rem。因此爲了提升開發效率,可使用px轉化爲rem的插件。若是你使用sublimeText,能夠用 rem-unitjava
使用rem單位注意如下幾點:ios
在全部的單位中,font-size推薦使用px,而後結合媒體查詢進行重要節點的控制,這樣能夠知足突出或者弱化某些字體的需求,而非總體調整。chrome
縱向的單位能夠所有使用px,橫向的使用rem,由於移動設備寬度有限,而高度能夠無限向下滑動。但這也有特例,好比對於一些活動註冊頁面,須要在一屏幕內徹底顯示,沒有下拉,這時候全部縱向或者橫向都應該使用rem做爲單位。如圖:gulp
左圖的表單高度單位因爲下邊空距較大,使用px在不一樣屏幕顯示更加;而右邊的活動註冊頁因爲不能出現滾動條,全部的衆向高度、margin、padding都應該使用rem。axios
3. border、box-shadow、border-radius等一些效果應該使用px做爲單位。api
可能你們不明白什麼叫"基於接口返回數據的屬性注入",在此以前,先說一下表單數據的綁定方式,一個重要的點是有幾份表單就分開幾個表單對象進行數據綁定。
已上圖公積金查詢爲例,因爲不一樣城市會有不一樣的查詢要素,可能登錄方式只有一種,也可能有幾種。好比上圖有三種登錄方式,在使用vue佈局時,有兩種方案。一是隻創建一個表單用於數據綁定,點擊按鈕觸發判斷;而是有幾種登錄方式創建幾個表單,用一個字段標識當前顯示的表單。因爲使用第三方的接口,一開始也沒有先進行接口返回數據結構的查看,採用了第一種錯誤的方式,錯誤一是每種登錄方式下面的登錄要素的數量也不一樣,錯誤二是數據綁定在同一個表單data下,當用戶在用戶名登錄方式輸入用戶名密碼後,切換到客戶號登錄方式,就會出現數據錯亂的狀況。
解決完佈局問題後,咱們須要根據設計圖定義一些狀態,好比當前登錄方式的切換、贊成受權狀態的切換、按鈕是否能夠點擊的狀態、是否處於請求中的狀態。固然還有一些app穿過來的數據,這裏就忽略了。
1 data: { 2 tags: { 3 arr: [''], 4 activeIndex: 0 5 }, 6 isAgreeProxy: true, 7 isLoading: false 8 }
接着審查一下接口返回的數據,推薦使用chrome插件postman,好比呼和浩特的登錄要素以下:
{ "code": 2005, "data": [ { "name": "login_type", "label": "身份證號", "fields": [ { "name": "user_name", "label": "身份證號", "type": "text" }, { "name": "user_pass", "label": "密碼", "type": "password" } ], "value": "1" }, { "name": " login_type", "label": "公積金帳號", "fields": [ { "name": "user_name", "label": "公積金帳號", "type": "text" }, { "name": "user_pass", "label": "密碼", "type": "password" } ], "value": "0" } ], "message": "登陸要素請求成功" }
能夠看到呼和浩特有兩種受權登錄方式,咱們在data中定義了一個loginWays,初始爲空數組,接着methods中定義一個請求接口的函數,裏面就是基於返回數據的基礎上爲上面fields對象注入一個input字段用於綁定,這就是所謂的基於接口返回數據的屬性注入。
1 methods: { 2 queryloginWays: function(channel_type, channel_code) { 3 var params = new URLSearchParams(); 4 params.append('channel_type', channel_type); 5 params.append('channel_code', channel_code); 6 axios.post(this.loginParamsProxy, params) 7 .then(function(res) { 8 console.log(res); 9 var code = res.code || res.data.code; 10 var msg = res.message || res.data.message; 11 var loginWays = res.data.data ? res.data.data : res.data; 12 // 查詢失敗 13 if (code != 2005) { 14 alert(msg); 15 return; 16 } 17 // 添加input字段用於v-model綁定 18 loginWays.forEach(function(loginWay) { 19 loginWay.fields.forEach(function(field) { 20 field.input = ''; 21 }) 22 }) 23 this.loginWays = loginWays; 24 this.tags.arr = loginWays.map(function(loginWay) { 25 return loginWay.label; 26 }) 27 }.bind(this)) 28 } 29 }
即便返回的數據有咱們不須要的數據也沒有關係,這樣保證咱們不會遺失進行下一步登錄所須要的數據。
這樣多個表單綁定數據問題解決了,那麼怎麼進行頁面間數據傳遞?若是是app傳過來,那麼一般使用URL拼接的方式,使用window.location.search得到queryString後再進行截取;若是經過頁面套入javaWeb中,那麼直接使用"${字段名}"就能獲取,注意要js中獲取java字段須要加雙引號。
computed: { // 真實姓名 realName: function() { return this.getQueryVariable('name') || '' }, // 身份證 identity: function() { return parseInt(this.getQueryVariable('identity')) || '' }, /*If javaWeb realName: function() { return this.getQueryVariable('name') || '' }, identity: function() { return parseInt(this.getQueryVariable('identity')) || '' }*/ }, methods: { getQueryVariable: function(variable) { var query = window.location.search.substring(1); var vars = query.split('&'); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split('='); if (decodeURIComponent(pair[0]) == variable) { return decodeURIComponent(pair[1]); } } console.log('Query variable %s not found', variable); } }
在進行接口請求時,咱們的頁面一般是在sublime的本地服務器或者vscode本地服務器預覽,因此請求接口會遇到跨域的問題。 在項目構建的時候一般咱們源代碼會放在src文件夾下,而後使用gulp進行代碼的壓縮、合併、圖片的優化(根據須要)等等,咱們會使用gulp。這裏解決跨域的問題能夠用gulp-connect結合http-proxy-middleware,此時咱們在gulp-connect中的本地服務器進行預覽調試。 gulpfile.js以下: 開發過程使用gulp server命令,監聽文件改動並使用livereload刷新;使用gulp命令進行打包。
1 var gulp = require('gulp'); 2 var concat = require('gulp-concat'); 3 var uglify = require('gulp-uglify'); 4 var autoprefixer = require('gulp-autoprefixer'); 5 var useref = require('gulp-useref'); 6 var connect = require('gulp-connect'); 7 var proxyMiddleware = require('http-proxy-middleware'); 8 // 定義環境變量,若爲 dev,則代理src目錄; 若爲prod,則代理dist目錄 9 var env = 'prod' 10 // 跨域代理 將localhost:8088/api 映射到 https://api.shujumohe.com/ 11 gulp.task('server', ['listen'], function() { 12 var middleware = proxyMiddleware(['/api'], { 13 target: 'https://api.shujumohe.com/', 14 changeOrigin: true, 15 pathRewrite: { 16 '^/api': '/' 17 } 18 }); 19 connect.server({ 20 root: env == 'dev' ? './src' : './dist', 21 port: 8088, 22 livereload: true, 23 middleware: function(connect, opt) { 24 return [middleware] 25 } 26 }); 27 }); 28 gulp.task('html', function() { 29 gulp.src('src/*.html') 30 .pipe(useref()) 31 .pipe(gulp.dest('dist')); 32 }); 33 gulp.task('css', function() { 34 gulp.src('src/css/main.css') 35 .pipe(concat('main.css')) 36 .pipe(autoprefixer({ 37 browsers: ['last 2 versions'], 38 cascade: false 39 })) 40 .pipe(gulp.dest('dist/css/')); 41 gulp.src('src/css/share.css') 42 .pipe(concat('share.css')) 43 .pipe(autoprefixer({ 44 browsers: ['last 2 versions'], 45 cascade: false 46 })) 47 .pipe(gulp.dest('dist/css/')); 48 gulp.src('src/vendors/css/*.css') 49 .pipe(concat('vendors.min.css')) 50 .pipe(autoprefixer({ 51 browsers: ['last 2 versions'], 52 cascade: false 53 })) 54 .pipe(gulp.dest('dist/vendors/css')); 55 return gulp 56 }); 57 gulp.task('js', function() { 58 return gulp.src('src/vendors/js/*.js') 59 .pipe(concat('vendors.min.js')) 60 .pipe(uglify()) 61 .pipe(gulp.dest('dist/vendors/js')); 62 }); 63 gulp.task('img', function() { 64 gulp.src('src/imgs/*') 65 .pipe(gulp.dest('dist/imgs')); 66 }); 67 gulp.task('listen', function() { 68 gulp.watch('./src/css/*.css', function() { 69 gulp.src(['./src/css/*.css']) 70 .pipe(connect.reload()); 71 }); 72 gulp.watch('./src/js/*.js', function() { 73 gulp.src(['./src/js/*.js']) 74 .pipe(connect.reload()); 75 }); 76 gulp.watch('./src/*.html', function() { 77 gulp.src(['./src/*.html']) 78 .pipe(connect.reload()); 79 }); 80 }); 81 gulp.task('default', ['html', 'css', 'js', 'img']);