摘要:年前放假的最后一天,我們上線了獨家記憶活動宣傳頁。微信分享主要代碼參考獨家記憶當時光凝固,當回憶定格。這是屬于我和的獨家記憶。
年前放假的最后一天,我們上線了「My Flyme 獨家記憶」 H5 活動宣傳頁。
因種種原因,直到放假前幾天,才突然要求我們參與并開始項目的前端部分。此時大概的情況是:所有數(shù)據(jù)已計算完畢;后端接口已完成待聯(lián)調(diào);交互視覺只出了不到四分之一(一共二十多個頁面);我們平時以中后臺項目為主,這種活動頁從未涉及。我們真正介入時距離上線時間點只有四天,在這種背景下,已經(jīng)談不上探討什么樣的技術(shù)選型最佳,只能是越快越容易實現(xiàn)越好。于是拉上了所有用得上的前端成員一起努力,最終算是在要求時間點上實現(xiàn)了上線目標。
這種活動宣傳性質(zhì)的頁面雖然用不上太復(fù)雜的邏輯,但也有很多后臺項目涉及不到的細節(jié),讓我們踩了不少的坑。這里針對項目開發(fā)過程中涉及的一些主要技術(shù)點作一下總結(jié)回顧。
「My Flyme 獨家記憶」(DEMO, 數(shù)據(jù)為隨機制造):https://lzw.me/pages/demo/myf...
1 項目特點多頁滑動效果,頁面多,動畫元素細節(jié)多,動畫效果簡單
個人頁(主頁面)需 Flyme 賬號登錄,自有應(yīng)用內(nèi)要盡量實現(xiàn)免登錄
將會在魅族主流應(yīng)用和社區(qū)里推廣
可分享到微信、微博等主流社交媒體
2 Slider 實現(xiàn)多頁翻屏滑動的效果有很多開源的實現(xiàn),當然希望盡量的簡單自己實現(xiàn)也不是很復(fù)雜。我們選擇的是百度開源的 iSlider,iSlider 是一款非常優(yōu)秀的翻頁滑動組件。除此之外,還有很多成熟的開源實現(xiàn)可選用:
swiper http://www.swiper.com.cn
iscroll https://github.com/cubiq/iscroll
fullpage.js https://github.com/alvarotrigo/fullPage.js/
Scrollify https://github.com/lukehaas/Scrollify
onepage-scroll https://github.com/peachananr/onepage-scroll
3 移動屏幕適配移動端屏幕適配常用的方案有如下三種:
固定高度,寬度自適應(yīng)
固定寬度/高度,viewport 縮放
rem 做寬度,viewport 縮放
3.1 高度優(yōu)先、viewport 等比縮放適配方案因為涉及多頁大量的動畫元素,只能是絕對定位來快速布局,我們采取了第二種方案:頁面以 320x640 作為基礎(chǔ)大小布局,在移動端根據(jù)實際的頁面大小等比縮放。主要適配代碼參考:
+function () { function isMobile() { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobi/i.test(navigator.userAgent); } function setScale() { var pageScale = 1; if (window.top !== window) { return pageScale; } var width = document.documentElement.clientWidth || 360; var height = document.documentElement.clientHeight || 640; if (width / height >= 360 / 640) { // 高度優(yōu)先 pageScale = height / 640; } else { pageScale = width / 360; } var content = "width=" + 360 + ", initial-scale=" + pageScale + ", maximum-scale=" + pageScale + ", user-scalable=no"; document.getElementById("viewport").setAttribute("content", content); return pageScale; } if (isMobile()) { setScale(); } else { try { document.getElementsByTagName("html")[0].classList.add("pc"); } catch (e) {} } }
這種方案以高度優(yōu)先,以使得全部內(nèi)容都能夠出現(xiàn)在可視區(qū)域。但有一個問題是,在 webview 內(nèi)寬高比大于 9/16,于是實際采用了高度的比例縮放,基礎(chǔ)寬度縮放后會小于屏幕寬度,由于涉及動畫的元素采用了絕對定位,這導(dǎo)致這些元素顯示上偏左,右邊出現(xiàn)較多的空白。
3.2 絕對定位元素的微調(diào)方法對于這種問題,我們的@零零柒同學(xué)想到了一種簡單快速的解決方案:取得基礎(chǔ)寬度與真實寬度的縮放比,將所有絕對定位的元素按照該縮放比重新計算 left 位移。主要代碼參考:
import $ from "./libs/zepto"; const width = document.documentElement.clientWidth || 360; const height = document.documentElement.clientHeight || 640; let pageScale = 1; if (width / height >= 360 / 640) { pageScale = height / 640; } const offset = (width - pageScale * 360) / 2; // 每當頁面切換后調(diào)用 export function positionFix(dom) { if (pageScale === 1 || !offset) { return; } // 為一個頁面 const $dom = $(dom); if ($dom.hasClass("position-fixed")) { return; } $dom.find(".text-box i, img").forEach((dom, i) => { let $this = $(dom), left; // 只修改絕對定位的元素 if ($this.css("position") !== "absolute") { return; } left = +($this.css("left").replace("px", "")); $this.css("left", (left + offset) + "px"); // console.log($(dom).css("left")); }); $dom.addClass("position-fixed"); }3.3 設(shè)計稿圖片等比縮放方法
頁面縮放解決了不同屏幕大小的布局一致性。另外涉及的一個問題是,設(shè)計稿圖片大小如何進行等比縮放?
這個問題也很簡單,圖片引用直接設(shè)置 width 以縮放到合適大??;雪碧圖上的圖片則按照 360x640 的頁面大小進行縮放:
對于絕對定位的元素,使用 transform: scale(0.333) 進行變換縮放
對于流式布局的元素,使用 zomm(0.333) 進行縮放
3.4 快速布局方法還有一個值得一提的問題是,如何做到布局元素與設(shè)計稿完全一致?
這個問題的解決方法是:使用靜態(tài)的設(shè)計稿圖片作為全屏背景,通過調(diào)整各元素到對應(yīng)位置,從而實現(xiàn)快速定位。我們的一位同學(xué)給出了這個方法,并且給出了一個讓頁面元素可拖動并設(shè)置最終位置(left/right值)的 jQuery 插件,這使得我們的頁面布局變得簡單而高效。
4 HTML5 動畫實現(xiàn)動畫實現(xiàn)方案一般來說可以選擇CSS3 動畫、引入游戲引擎或使用 svg/canvas。
4.1 CSS3 動畫該方案技術(shù)成本簡單,任何前端開發(fā)者都能快速上手,但細節(jié)實現(xiàn)上工作量大。
從簡單快速開始的角度來說,CSS3 動畫是我們的唯一選擇。使用 CSS3 動畫需要特別注意一點:修改 DOM 會導(dǎo)致頁面重繪,在移動端容易出現(xiàn)卡頓現(xiàn)象。所以應(yīng)盡可能避免使用會修改 DOM 的 css 屬性,只使用 transform 實現(xiàn)動畫變換效果。
我們的頁面動畫都是循環(huán)運動的,全部需要對照動效設(shè)計逐一還原實現(xiàn),花費了大量的人力和時間成本。實現(xiàn)上主要使用了 animation、keyframe、transform 屬性。
此外,對于常見的入場顯示/滑入等動畫效果,只需要使用 transform 和 transition 即可實現(xiàn)需求。對于 css 動畫也有很多優(yōu)秀而成熟的動畫庫可用,一些參考:
animate.css https://github.com/daneden/animate.css
magic.css https://github.com/miniMAC/magic
Hover.css http://ianlunn.github.io/Hover/
velocity.js https://github.com/julianshapiro/velocity
anime.js https://github.com/juliangarnier/anime
下面簡單介紹一下另外的兩種動畫實現(xiàn)方案。
4.2 引入游戲引擎方案使用 h5 游戲引擎可大幅度降低工作量,能夠相對容易地實現(xiàn)復(fù)雜動畫效果,但需要經(jīng)驗避免入深坑,有較高學(xué)習(xí)成本,并且需要設(shè)計師深度配合。一些參考:
Hilo https://github.com/hiloteam/Hilo
Phaser https://github.com/photonstorm/phaser
pixi.js https://github.com/pixijs/pixi.js
melonjs https://github.com/melonjs/melonjs
playcanvas https://github.com/playcanvas/engine
LayaAir http://www.layabox.com
白鷺引擎 https://www.egret.com
4.3 使用 svg/canvas 操作庫使用 svg/canvas/webGL 實現(xiàn)的動畫效果會比較好,但實現(xiàn)工作量較大,對實踐經(jīng)驗也有較高的要求。成熟的相關(guān)庫參考:
createJs https://github.com/CreateJS
snap.svg https://github.com/adobe-webplatform/Snap.svg
svg.js https://github.com/svgdotjs/svg.js
d3.js https://d3js.org
threes.js https://threejs.org
5 微信分享由于第一次做這種活動頁,沒有特別注意到微信內(nèi)分享的問題,直到上線時才發(fā)現(xiàn),分享出去的效果實在太難看,這導(dǎo)致幾位留守到最后的同事緊急探討協(xié)調(diào)方案,幾乎整晚沒睡覺。
5.1 微信 jssdk 分享 API微信內(nèi)開發(fā)應(yīng)注意這幾點:
下載微信開發(fā)者工具(或 TBS Studio),以調(diào)試微信內(nèi)頁面
需要通過認證的公眾號或訂閱號,取得微信 jssdk 分享接口所需的 appId 和 signature
需要后端 API 管理 signature 簽名的生成與緩存
window.history.pushState/replaceState 修改了 URL 時需要重新生成 signature 簽名。由于沒有仔細閱讀文檔并意識到這一點,在這個問題上坑了比較多的時間。
我們最終協(xié)調(diào)到一個部門的訂閱號,并使用他們已實現(xiàn)了的后端 token 簽名生成 API 來實現(xiàn) jssdk 的分享 API,在 nginx 層對該 API 代理轉(zhuǎn)發(fā)解決跨域安全性相關(guān)問題。微信分享主要代碼參考:
const isWeixinBrowser = /micromessenger/.test(navigator.userAgent.toLowerCase()); const wxJsdk = "http://res.wx.qq.com/open/js/jweixin-1.1.0.js"; const jsApiList = ["checkJsApi", "onMenuShareTimeline", "onMenuShareAppMessage", "onMenuShareQQ", "onMenuShareWeibo"]; let opts = { title: "My Flyme 獨家記憶", desc: "當時光凝固,當回憶定格?;厥?016 ,我與 Flyme 的點點滴滴都在這里。這是屬于我和 Flyme 的獨家記憶。", link: "", imgUrl: "" }, loadedwx = false; function initShareEvent(wx) { const option = { ...opts, trigger: function (res) {console.log("trigger", res)}, success: function (res) { console.log("已分享", res) }, cancel: function (res) { console.log("已取消", res) }, fail: function (res) { console.log(JSON.stringify(res)) } }; wx.onMenuShareAppMessage(option); // 分享給朋友 wx.onMenuShareTimeline(option); // 分享到朋友圈 wx.onMenuShareQQ(option); // 分享到QQ wx.onMenuShareWeibo(option); // 分享到微博 wx.onMenuShareQZone(option); // 分享到QZone } function checkJsApi(wx) { wx.checkJsApi({ jsApiList, success: () => initShareEvent(wx), error: err => console.log("checkJsApi error: ", err) }); } function initConfig(wx) { // 特別注意,這里 link 必須使用當前頁面的 URL 地址,否則會失敗! opts.link = encodeURIComponent(document.location.href.split("#")[0]); return $.ajax({ url: "/wechat_api/get_js_ticket?&url=" + opts.link, dataType:"jsonp", //指定為jsonp類型 jsonp:"callback" }).done((res) => { wx.config({ debug: process.env.NODE_ENV === "development", appId: "wx0000000000000000", nonceStr: res.data.nonceStr, timestamp: res.data.timestamp, signature: res.data.signature, jsApiList }); }); } export default options => { if (loadedwx || !isWeixinBrowser) { return } require([wxJsdk], (wx) => { loadedwx = true; $.extend(true, opts, options); initConfig(wx); wx.ready(() => checkJsApi(wx)); wx.error((res) => console.error("出錯了:", res.errMsg)); }); }5.2 不走微信 jssdk 的取巧方法
微信分享 API 需要公眾號或訂閱號,臨時的活動開發(fā)可能來不及折騰,那么一個折中的辦法是這樣的:在頁面頭部 img 標簽設(shè)置分享顯示的圖片,設(shè)置高度和寬度為 0。示例:
微信會提取頁面標題和第一張圖片,作為朋友圈分享的標題和縮略圖。使用 jssdk 方式分享到朋友圈的效果也是只有標題和縮略圖,所以效果上沒有區(qū)別。比較大的區(qū)別是,“發(fā)送給好友”時沒有描述,描述位置變成了頁面 URL 地址。
6 性能優(yōu)化相關(guān)由于時間緊而且設(shè)計稿是逐步給到的,很多細節(jié)的優(yōu)化都沒法去做。最終上線的版本首屏大小約 1.3M,在弱網(wǎng)下的加載時間會比較久一些,可優(yōu)化空間還比較大。這里探討一下我們主要考慮到的幾個點。
6.1 頁面資源異步加載一共二十多個頁面,我們按每頁一個 html 模板和一個 less 文件的方式,按頁面分工開發(fā),在 index.html 頁面以 script 模板方式引入,由 fis3 實現(xiàn)模板嵌入。通過 ajax 拿到數(shù)據(jù)后,根據(jù)數(shù)據(jù)替換模板中的數(shù)據(jù)占位符,并進行頁面切割,然后生成 iSlider 需要的數(shù)據(jù)配置項。這樣做的好處是 html 內(nèi)容未寫入到 DOM 時,涉及的靜態(tài)資源圖片不會被加載。
iSlider 默認至少加載 3 個頁面,每一時刻也最多保存三個頁面實例。于是首屏加載了三個頁面,這正好符合我們的目的。
另外要提到的一點是,弱網(wǎng)下不同圖片下載的時差較大,會使得不同位置的圖片動畫斷斷續(xù)續(xù)地出現(xiàn)。為了避免這種不好的效果,我們使用了一個簡單的圖片預(yù)加載機制,在預(yù)加載完首屏涉及的圖片資源后才隱藏 loading 顯示頁面。
6.2 webp 支持該項目涉及圖片資源 500 多張,只有手繪文字圖片做了雪碧圖處理。現(xiàn)在的移動端基本都支持 webp,使用 webp 是必須的。實際上使用 webp 后,圖片目錄的大小減小了 60%。
以前大家都是用智圖這種在線工具處理少量的圖片,搜索了一下,居然沒有找到現(xiàn)成的批量生成 webp 的工具庫,于是寫了一個批量生成方法。這兩天整理完善了一下,算是造了一個小輪子,需要的同學(xué)可以關(guān)注下,地址在這里:
webp 批量轉(zhuǎn)換:https://github.com/lzwme/webp-batch-convert
7 應(yīng)用內(nèi)登陸/分享由于要在 Flyme 自帶的近十個主要應(yīng)用內(nèi)作推廣入口,涉及到兩個問題:應(yīng)用內(nèi)分享和應(yīng)用內(nèi)免登錄。
在協(xié)調(diào)這一塊時發(fā)現(xiàn),各應(yīng)用都是獨自制定的各不相同的 webview 內(nèi)相關(guān) js 接口和規(guī)范,同一應(yīng)用不同版本的實現(xiàn)也可能有差異,或者根本沒有相關(guān)實現(xiàn);有規(guī)范的文檔也不夠齊全,并且都沒有示例參考;沒有各應(yīng)用的開發(fā)測試版本來做調(diào)試。于是花了不少時間各種咨詢,踩了不少的坑,效果也還是不盡人意,最終只在魅族瀏覽器上做到了期望的效果。
沒有統(tǒng)一規(guī)范,各自造輪子,于是這種跨部門跨應(yīng)用的功能需求變得如此艱難。導(dǎo)致這種現(xiàn)象的存在因素很多,可知的一點是也和公司內(nèi)前端人員處于邊緣化地位的現(xiàn)實有關(guān)。過去的一年里,基礎(chǔ)技術(shù)支撐部門技術(shù)平臺做了一套 hybridApp 解決方案,@chemdemo 同學(xué)還將 JSBridge 部分抽離開源了出來:https://github.com/chemdemo/hybrid-js??赡苁侨鄙俑邔幼銐虻南嚓P(guān)意識和支持力度,并沒有在各業(yè)務(wù)軟件內(nèi)得到廣泛應(yīng)用,反而主要靠內(nèi)部前端圈間溝通傳播。不過這套方案為了簡潔只實現(xiàn)了很少的通用 API 和可擴展方法,并沒有繼續(xù)實現(xiàn)各種業(yè)務(wù)適用的通用性擴展功能,自然也沒有我們想要的應(yīng)用內(nèi)分享和 Flyme 免登錄這兩個功能。
對于這個問題有兩點總結(jié):
統(tǒng)一的公共 SDK 的重要性:避免重復(fù)造輪子,健壯且具有一致性的 API、完善的文檔。
再好的文檔不如一個 demo
8 工程化問題項目初期使用 webpack 進行構(gòu)建,但由于我們平時的經(jīng)驗以 fis3 為主,webpack 過于靈活的配置特性使得一些工程化需求需要花時間探索。在我們接手項目后一起討論了一下,果斷轉(zhuǎn)為熟悉的 fis3 構(gòu)建體系。使用 fis3 主要解決的問題有:
less 編譯
es6 編譯
js/css 壓縮合并
頁面模板嵌入
發(fā)布時 CDN 多帶帶域名的適配
發(fā)布時符合內(nèi)部運維體系線上發(fā)布規(guī)范的目錄路徑修正
相比較為靈活的 webpack,fis3 更注重流程化整體解決方案,簡單的數(shù)十行配置即可實現(xiàn)各種工程化需求。不過 fis3 的發(fā)展現(xiàn)在似乎進入了一個瓶頸期/穩(wěn)定期,社區(qū)中對于在 rollup 和 webpack 中大熱的 tree-shaking 等技術(shù)幾乎都沒有什么反應(yīng)。希望它不要沒落了,能有更多的創(chuàng)新吧。有兩點期望:走國際化路線,出英文文檔與社區(qū)支持,向國際頂級項目看進;跟進參考業(yè)界最新的工程化理念,如有必要出個 fis4 也未嘗不可。
9 運維發(fā)布問題由于涉及到跨部門合作,也沒有太多的時間,項目起初放在了內(nèi)部的 gitlab 平臺,沒有走 git+gerrit+jenkins+運維發(fā)布平臺 這一內(nèi)部完整的體系。這樣做在前期省去了項目創(chuàng)建、各種權(quán)限申請等一堆需要協(xié)調(diào)溝通的事情,開發(fā)協(xié)作效率也比較高,但到了發(fā)布的階段就突顯出了問題:每次發(fā)布都需要由運維人員手動操作,協(xié)調(diào)發(fā)布很花費時間。
另外靜態(tài)頁面也沒有獨立出來,想當然地簡單的扔到后端目錄中,結(jié)果導(dǎo)致前端的修改需要后端也必須作修改發(fā)布,增加了前后端協(xié)調(diào)的時間成本。
于是,在首次發(fā)布后又進行的幾次小迭代中,每次迭代發(fā)布都涉及到多人手動協(xié)調(diào),十分的浪費時間。
總結(jié)一句話:項目構(gòu)建盡量與已有的成熟的規(guī)范一致,以少走彎路。
10 其他最后列舉一些移動端 H5 開發(fā)可參考的內(nèi)容:
真機調(diào)試 https://github.com/jieyou/remote_inspect_web_on_real_device
vConsole: 客戶端內(nèi) H5 調(diào)試 https://github.com/WechatFE/vConsole
移動端布局終極解決方案 https://github.com/imochen/hotcss
mobileHack https://github.com/RubyLouvre/mobileHack
小結(jié)這是我們第一次嘗試這種活動頁,在如此緊湊的時間節(jié)點下,沒有什么高大上的東西,更多的是各種采坑嘗試的實踐過程。以上列舉的內(nèi)容算是對本次開發(fā)實踐做一個總結(jié)記錄,采用的相關(guān)實現(xiàn)方案也可作后續(xù)參考。歡迎探討分享你們的經(jīng)驗。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/116458.html
摘要:年前放假的最后一天,我們上線了獨家記憶活動宣傳頁。微信分享主要代碼參考獨家記憶當時光凝固,當回憶定格。這是屬于我和的獨家記憶。 年前放假的最后一天,我們上線了「My Flyme 獨家記憶」 H5 活動宣傳頁。 因種種原因,直到放假前幾天,才突然要求我們參與并開始項目的前端部分。此時大概的情況是:所有數(shù)據(jù)已計算完畢;后端接口已完成待聯(lián)調(diào);交互視覺只出了不到四分之一(一共二十多個頁面);我...
摘要:本文系魅族架構(gòu)師胡成元,在直聘主辦的直聘學(xué)院對話架構(gòu)師活動上的分享整理,介紹魅族應(yīng)用商店云端架構(gòu)實踐的總結(jié)。年加入魅族,一直致力于移動應(yīng)用架構(gòu)研發(fā),提升產(chǎn)品體驗和研發(fā)效率。目前主要負責(zé)魅族應(yīng)用商店的研發(fā)工作,關(guān)注服務(wù)化分布式大數(shù)據(jù)等領(lǐng)域。 本文系魅族Flyme架構(gòu)師胡成元,在Boss直聘主辦的直聘學(xué)院「對話架構(gòu)師」活動上的分享整理,介紹魅族應(yīng)用商店云端架構(gòu)實踐的總結(jié)。 showImg(...
閱讀 1623·2023-04-26 01:36
閱讀 2785·2021-10-08 10:05
閱讀 2835·2021-08-05 09:57
閱讀 1589·2019-08-30 15:52
閱讀 1252·2019-08-30 14:12
閱讀 1376·2019-08-30 11:17
閱讀 3183·2019-08-29 13:07
閱讀 2504·2019-08-29 12:35