摘要:前言上個(gè)月月底開(kāi)源組開(kāi)源了使用適配人人企業(yè)版專(zhuān)業(yè)版的前端工程具體詳情見(jiàn)人人企業(yè)版適配發(fā)布。當(dāng)然,也督促自己產(chǎn)出一篇相關(guān)的文章,來(lái)記錄這次有趣的學(xué)習(xí)之旅。
Created by huqi at 2019-5-5 13:01:14
Updated by huqi at 2019-5-20 15:57:37
前言
上個(gè)月月底@D2開(kāi)源組 開(kāi)源了使用 D2Admin 適配 人人企業(yè)版(專(zhuān)業(yè)版) 的前端工程--d2-admin-renren-security-enterprise,具體詳情見(jiàn)?D2Admin 人人企業(yè)版適配發(fā)布。由于最近有開(kāi)發(fā)后臺(tái)管理系統(tǒng)的需求,加上其他諸多因素,如:想學(xué)習(xí)優(yōu)秀的開(kāi)源項(xiàng)目、剛好參加@jsliang 組織的暴走前端、之前項(xiàng)目使用過(guò)renren-fast-vue等等,于是乎萌生了根據(jù)commits學(xué)習(xí)了解d2-admin如何改造renren-security前端的想法。當(dāng)然,也督促自己產(chǎn)出一篇相關(guān)的文章,來(lái)記錄這次有趣的學(xué)習(xí)之旅。
前置準(zhǔn)備
所謂“工欲善其事必先利其器”,連我這樣的Copy攻城獅都要搭建的前端基礎(chǔ)開(kāi)發(fā)環(huán)境,都9102年啦,再?zèng)]有node環(huán)境都沒(méi)法進(jìn)行前端開(kāi)發(fā)了,再不濟(jì)運(yùn)行d2-admin的環(huán)境總該有吧!
安裝環(huán)境
這里請(qǐng)參考D2 Admin快速上手部分:?安裝環(huán)境
Fork D2-Admin@1.6.18
這里緊跟@FairyEver 大大的思路,基于D2-Admin@1.6.18 開(kāi)發(fā)。當(dāng)然也可以通過(guò)D2 Admin CLI來(lái)初始化項(xiàng)目,具體操作參照:?下載項(xiàng)目
了解D2Admin項(xiàng)目結(jié)構(gòu)
有過(guò)開(kāi)發(fā)經(jīng)歷的同學(xué)在項(xiàng)目開(kāi)發(fā)之前一般都有過(guò)項(xiàng)目結(jié)構(gòu)搭建的經(jīng)歷,當(dāng)然如果您不幸和我一樣只會(huì)用別人搭建好的工程腳手架,那您一定會(huì)先了解整個(gè)項(xiàng)目目錄結(jié)構(gòu),不然還真不知道源碼要寫(xiě)在哪里。
├─ docs // 文檔 ├─ packages // 額外的包 ├─ public // 公共文件 ├─ src // 源碼目錄 │ ├─ assets // 資源 │ │ ├─ icons │ │ ├─ image │ │ ├─ library │ │ └─ style │ ├─ components // 組件 │ │ ├─ charts │ │ ├─ core │ │ └─ demo │ ├─ i18n // 多語(yǔ)言 │ ├─ menu // 菜單 │ ├─ mock // 模擬數(shù)據(jù) │ ├─ pages // 頁(yè)面 │ ├─ plugin // 插件 │ ├─ router // 路由 │ ├─ store // vuex │ ├─ utils │ ├─ App.vue │ └─ main.js ├─ tests // 測(cè)試文件 ├─ .browserslistrc // 瀏覽器兼容設(shè)置 ├─ .env // 環(huán)境變量 ├─ .env.development // 開(kāi)發(fā)環(huán)境變量 ├─ .env.nomock // nomock環(huán)境變量 ├─ .env.travis // 生成環(huán)境變量 ├─ .eslintignore // ESLint忽略 ├─ .eslintrc.js // ESLint配置 ├─ .gitignore // git忽略 ├─ .postcssrc.js // postcss配置 ├─ .travis.yml // 持續(xù)集成服務(wù) ├─ babel.config.js // babel配置 ├─ cdnrefresh-dirs.txt // cdn設(shè)置 ├─ jest.config.js // jest設(shè)置 ├─ LICENSE // 開(kāi)源協(xié)議 ├─ package-lock.json // 包文件鎖版本 ├─ package.json // 包文件 ├─ qiniu-config // 七牛云配置 ├─ qshell // 七牛API服務(wù)命令行工具 ├─ README.md |— README.zh.md ├─ vue.config.js // vue配置
刪除無(wú)關(guān)文件
刪除.browserslistrc、.env.nomock、.env.travis 、.gitignore、.postcssrc.js、.travis.yml、cdnrefresh-dirs.txt 、package-lock.json、 qiniu-config 、qshell、README.zh.md、README.md、doc/image、package/*。具體可查看:?刪除暫時(shí)未用到模塊
修改package.json
移除暫時(shí)未用到的包,如多語(yǔ)言,這個(gè)版本將簡(jiǎn)化多語(yǔ)言目錄結(jié)構(gòu),如圖表庫(kù)、富文本編輯、右鍵菜單等:
countup.js
echarts
github-markdown-css
highlight.js
marked
mockjs
simplemde
v-charts
v-contextmenu
vue-grid-layout
vue-i18n
vue-json-tree-view
vue-splitpane
vue-ueditor-wra
@kazupon/vue-i18n-loader
刪除build:nomock命令,增加環(huán)境變量文件.env、.env.production、.env.production.sit、.env.production.uat等。至此,可以通過(guò)npm install 或 yarn來(lái)安裝項(xiàng)目依賴(lài),并通過(guò)npm run dev之類(lèi)的指令運(yùn)行項(xiàng)目,具體指令可查看 package.json 文件中 scripts 部分。
重寫(xiě)國(guó)際化
至于為什么要重寫(xiě),要問(wèn)大佬了。我也只能妄加揣測(cè):簡(jiǎn)化結(jié)構(gòu)!之前的結(jié)構(gòu)是一個(gè)index.js+lang文件夾,lang文件夾里又包含多個(gè)語(yǔ)言文件夾,現(xiàn)在的結(jié)構(gòu)直接了當(dāng)--index.js+多個(gè)語(yǔ)言js文件。關(guān)于國(guó)際化我也只是很膚淺的了解,雖然之前接觸過(guò)的項(xiàng)目也做過(guò),里邊坑的確挺多的,除了基本的翻譯還要結(jié)合當(dāng)?shù)氐奈幕?xí)俗,這里就不展開(kāi)討論,搜索關(guān)鍵字i18n便有眾多的解決方案。回到大佬@FairyEver 的源碼,跟著他了解一下vue-i18n的使用:
安裝依賴(lài)
npm install vue-i18n
main.js中引入
// ... // i18n import i18n from "@/i18n" // ... new Vue({ i18n, // ... )}
新建語(yǔ)言包,構(gòu)建js
核心代碼:
// 引入相關(guān)依賴(lài)及語(yǔ)言包 import Vue from "vue" import VueI18n from "vue-i18n" import Cookies from "js-cookie" // 附帶引入element-ui的多語(yǔ)言切換 import zhCNLocale from "element-ui/lib/locale/lang/zh-CN" import zhTWLocale from "element-ui/lib/locale/lang/zh-TW" import enLocale from "element-ui/lib/locale/lang/en" // 引入語(yǔ)言包 import zhCN from "./zh-CN" import zhTW from "./zh-TW" import enUS from "./en-US" Vue.use(VueI18n) // 定義使用的語(yǔ)言 export const messages = { "zh-CN": { "_lang": "簡(jiǎn)體中文", ...zhCN, ...zhCNLocale }, "zh-TW": { "_lang": "繁體中文", ...zhTW, ...zhTWLocale }, "en-US": { "_lang": "English", ...enUS, ...enLocale } } // 默認(rèn)從cookie中讀取或設(shè)置為中文 export default new VueI18n({ locale: Cookies.get("language") || "zh-CN", messages })
語(yǔ)言包以灣灣繁體為例:
// 定義語(yǔ)言對(duì)象 const t = {} t.loading = "加載中..." // 構(gòu)建對(duì)象 t.brand = {} t.brand.lg = "人人權(quán)限企業(yè)版" t.brand.mini = "人人" // ... export default t
使用
// 選擇語(yǔ)言 import Cookies from "js-cookie" import { messages } from "@/i18n" export default { name: "app", watch: { "$i18n.locale": "i18nHandle" }, created () { this.i18nHandle(this.$i18n.locale) }, methods: { i18nHandle (val, oldVal) { Cookies("language", val) document.querySelector("html").setAttribute("lang", val) document.title = messages[val].brand.lg // 非登錄頁(yè)面,切換語(yǔ)言刷新頁(yè)面 if (this.$route.name !== "login" && oldVal) { window.location.reload() } } } }
頁(yè)面中使用,如:
// template {{ $t("login.motto.text") }} :placeholder="$t("login.form.placeholderUsername")" // script this.$t("login.motto.text")
檢驗(yàn)成果
實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn)。
修改i18n/index.js 將locale改為灣灣繁體,就能直觀的看到title的變化,(別問(wèn)我為啥頁(yè)面上的文字怎么沒(méi)變化?因?yàn)閷?xiě)死為簡(jiǎn)體中文啦!)
注意: 實(shí)現(xiàn)vue-i18n+element-ui多語(yǔ)言切換需手動(dòng)注冊(cè)如,參考element-ui國(guó)際化:
// i18n import i18n from "@/i18n" // Element import ElementUI from "element-ui" import "element-ui/lib/theme-chalk/index.css" // Element Vue.use(ElementUI, { i18n: (key, value) => i18n.t(key, value) })
文字部分全部修改為國(guó)際化后,就可以看到明顯的效果啦:
多語(yǔ)言切換
既然有了國(guó)際化的基礎(chǔ),那么實(shí)現(xiàn)一個(gè)多語(yǔ)言切換的小功能應(yīng)該是水到渠成。來(lái)看看@FairyEver是怎么教的! 偶然間看到d2-admin中的標(biāo)簽可以使用flex這個(gè)屬性,感到很好奇。
flex,對(duì)于新世紀(jì)的前端開(kāi)發(fā)來(lái)說(shuō)最熟悉不過(guò),但是標(biāo)簽上直接寫(xiě)flex屬性,作為很水很水的老菜鳥(niǎo)卻是孤落寡聞,不過(guò)職業(yè)病的直覺(jué)告訴我一定是跟flex布局有關(guān)。于是我按圖索驥,先翻閱了一下package.json,里邊果然找到一個(gè)flex.css的依賴(lài)包。大概實(shí)現(xiàn)怎樣的效果呢?我的認(rèn)知是通過(guò)標(biāo)簽的flex屬性,無(wú)需寫(xiě)css即可實(shí)現(xiàn)flex布局,flex.css內(nèi)部通過(guò)定義屬性選擇器樣式來(lái)實(shí)現(xiàn)flex布局,更多關(guān)于flex.css請(qǐng)戳?flex.cc。
這里通過(guò)elemen-ui的el-dropdown實(shí)現(xiàn),通過(guò)command事件修改語(yǔ)言設(shè)置
$i18n.locale = command"> {{ $t("login.language") }} {{ language.label }} 對(duì)接人人驗(yàn)證碼
一般來(lái)說(shuō),做登錄頁(yè)的時(shí)候,我們或多或少會(huì)遇到驗(yàn)證碼的需求,對(duì)了,這里的驗(yàn)證碼指的是圖形驗(yàn)證碼。最簡(jiǎn)單的實(shí)踐是直接拿后臺(tái)給過(guò)來(lái)的圖片直接渲染的在頁(yè)面上,使用 img標(biāo)簽 或者 background-image 引入。之前做renren-fast-vue二次開(kāi)發(fā)的時(shí)候用的img標(biāo)簽,這里用的背景圖片,思路都一樣:拿后臺(tái)給的圖片直接渲染。眾所周知,Just do it!
定義獲取uuid的工具函數(shù):
/** * @description [ renren ] 獲取uuid */ util.getUUID = function () { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => { return (c === "x" ");
使用uuid獲取圖形驗(yàn)證碼
// 選擇語(yǔ)言 import Cookies from "js-cookie" import { messages } from "@/i18n" export default { name: "app", watch: { "$i18n.locale": "i18nHandle" }, created () { this.i18nHandle(this.$i18n.locale) }, methods: { i18nHandle (val, oldVal) { Cookies("language", val) document.querySelector("html").setAttribute("lang", val) document.title = messages[val].brand.lg // 非登錄頁(yè)面,切換語(yǔ)言刷新頁(yè)面 if (this.$route.name !== "login" && oldVal) { window.location.reload() } } } }
axios及登錄邏輯
自從擺脫了JQuery大法,阿賈克斯和我從此是陌生人,以至于面試官要我闡述阿賈克斯原理,我真是啞巴吃黃連,哦不,是啞口無(wú)言,一個(gè)以CP(Copy&Paste)為生的搬磚工,你們還指望他侃侃而談什么原理什么底層?至于什么axios攔截,總之,這一塊涉及到前后交互的知識(shí)點(diǎn)還是蠻多的,我也是七竅通靈六竅--一竅不通,勉勉強(qiáng)強(qiáng)解讀一下大佬的封裝:
登錄的話,需要調(diào)用api,按照d2-admin的項(xiàng)目結(jié)構(gòu),在src/api下定義api接口,如sys.login.js:axios簡(jiǎn)單封裝
// 引用相關(guān)依賴(lài)及方法 import axios from "axios" import { Message } from "element-ui" import Cookies from "js-cookie" import { isPlainObject } from "lodash" import qs from "qs" // import util from "@/libs/util" import router from "@/router" import store from "@/store" // 記錄和顯示錯(cuò)誤 function errorLog (error) { // 添加到日志 store.dispatch("d2admin/log/push", { message: "數(shù)據(jù)請(qǐng)求異常", type: "danger", meta: { error } }) // 打印到控制臺(tái) if (process.env.NODE_ENV === "development") { // util.log.danger(">>>>>> Error >>>>>>") console.log(error) } // 顯示提示 Message({ message: error.message, type: "error", duration: 5 * 1000 }) } // 創(chuàng)建一個(gè) axios 實(shí)例 const service = axios.create({ baseURL: process.env.VUE_APP_API, timeout: 1000 * 180, // 請(qǐng)求超時(shí)時(shí)間 withCredentials: true // 當(dāng)前請(qǐng)求為跨域類(lèi)型時(shí)是否在請(qǐng)求中協(xié)帶cookie }) /** * 請(qǐng)求攔截 */ service.interceptors.request.use( config => { // 在請(qǐng)求發(fā)送之前做一些處理,如設(shè)置headers config.headers["Accept-Language"] = Cookies.get("language") || "zh-CN" config.headers["token"] = Cookies.get("token") || "" // 默認(rèn)參數(shù) var defaults = {} // 防止緩存,GET請(qǐng)求默認(rèn)帶_t參數(shù) if (config.method === "get") { config.params = { ...config.params, ...{ "_t": new Date().getTime() } } } if (isPlainObject(config.data)) { // 純粹對(duì)象解構(gòu)賦值 config.data = { ...defaults, ...config.data } if (/^application/x-www-form-urlencoded/.test(config.headers["content-type"])) { // 序列化請(qǐng)求數(shù)據(jù) config.data = qs.stringify(config.data) } } return config }, error => { // 發(fā)送失敗 console.log(error) return Promise.reject(error) } ) /** * 響應(yīng)攔截 */ service.interceptors.response.use( response => { // 處理響應(yīng) if (response.data.code === 401 || response.data.code === 10001) { // clearLoginInfo() // alert("TODO clearLoginInfo") // TODO: 清除用戶信息 router.replace({ name: "login" }) return Promise.reject(response.data.msg) } if (response.data.code !== 0) { errorLog(new Error(response.data.msg)) return Promise.reject(response.data.msg) } return response.data.data }, error => { errorLog(error) return Promise.reject(error) } ) export default service
import request from "@/plugin/axios" export function login (data) { return request({ url: "/login", method: "post", data }) }
調(diào)用api進(jìn)行登錄:
// ... import { login } from "@api/sys.login" // ... submit () { this.$refs.loginForm.validate((valid) => { if (!valid) return login(this.form) .then(async res => { await this.login(res) this.$router.replace(this.$route.query.redirect || "/") }) .catch(this.updateUUID) }) } // ...
當(dāng)然還需要對(duì)數(shù)據(jù)進(jìn)行處理,比如登錄狀態(tài)持久化、設(shè)置vuex用戶信息等等,這里暫時(shí)只做簡(jiǎn)單的處理,另外安利一個(gè)vscode插件(乳溝您恰巧用的宇宙第一神器)--TODO Highlight,用來(lái)突出顯示代碼中的todo、fixme和其他注釋?zhuān)?tīng)說(shuō)老司機(jī)都在用。有時(shí),在將代碼發(fā)布到生產(chǎn)環(huán)境之前,在編碼時(shí)忘記查看添加的TODO。所以就有了這個(gè)拓展,提醒我們有一些筆記或者事情還沒(méi)有完成。mark一下!
標(biāo)準(zhǔn)化cookie使用
作為后臺(tái)管理系統(tǒng),免不了涉及到cookie的使用,按照大佬的思路,定義了工具集函數(shù)并基于js-cookie二次封裝了cookie。一般來(lái)說(shuō),cookie用得最多的就是get和set兩個(gè)方法。
如圖,能看到目前通過(guò)此次標(biāo)準(zhǔn)化封裝之后存的cookie的name都加了**d2admin-**的前綴。cookie簡(jiǎn)單封裝
import Cookie from "js-cookie" /** * @description 存儲(chǔ) cookie 值 * @param {String} name cookie name * @param {String} value cookie value * @param {Object} setting cookie setting */ export const cookieSet = function (name = "default", value = "", cookieSetting = {}) { let currentCookieSetting = { expires: 1 } Object.assign(currentCookieSetting, cookieSetting) Cookie.set(`d2admin-${process.env.VUE_APP_VERSION}-${name}`, value, currentCookieSetting) } /** * @description 拿到 cookie 值 * @param {String} name cookie name */ export const cookieGet = function (name = "default") { return Cookie.get(`d2admin-${process.env.VUE_APP_VERSION}-${name}`) } /** * @description 拿到 cookie 全部的值 */ export const cookieGetAll = function () { return Cookie.get() } /** * @description 刪除 cookie * @param {String} name cookie name */ export const cookieRemove = function (name = "default") { return Cookie.remove(`d2admin-${process.env.VUE_APP_VERSION}-${name}`) }
防止過(guò)度點(diǎn)擊
節(jié)流這個(gè)知識(shí)點(diǎn)我也是一直懵懵懂懂,經(jīng)常和防抖混淆,理解不深刻,還只是停留在字面意思理解上:函數(shù)節(jié)流是指定時(shí)間間隔內(nèi)只執(zhí)行一次,函數(shù)防抖是頻繁觸發(fā)只有間隔超過(guò)指定時(shí)間間隔才執(zhí)行。請(qǐng)參考debouncing-throttling-explained-examples 這里簡(jiǎn)單粗暴的用了lodash--一個(gè)一致性、模塊化、高性能的 JavaScript 實(shí)用工具庫(kù)。。 lodash中包含一系列數(shù)組、數(shù)字、對(duì)象、字符串等操作的API,當(dāng)然還有一些常用的工具函數(shù)如節(jié)流(throttle)、防抖(debounce)。
// ... import { debounce } from "lodash" // ... submit: debounce(function () { // ... }, 1000, { "leading": true, "trailing": false }) // _.debounce(func, [wait=0], [options={}]) // options.leading 與|或 options.trailing 決定延遲前后是先調(diào)用后等待,還是先等待后調(diào)用 // ...
前后對(duì)比:
未處理的時(shí)候,觸發(fā)的請(qǐng)求令人發(fā)指!
處理之后,控制臺(tái)讓人感覺(jué)很清爽
關(guān)于全局配置
項(xiàng)目做得太少了,尤其還不會(huì)java,對(duì)網(wǎng)站的全局配置這一塊的理解還停留在初級(jí)認(rèn)知階段。一般來(lái)說(shuō),在網(wǎng)頁(yè)開(kāi)發(fā)中往往一些版本控制、CDN靜態(tài)資源、api接口地址、常用的公共變量等都會(huì)寫(xiě)到window下面并提升至首頁(yè)方便管理,如網(wǎng)易一些爆款的H5中這種手法非常常見(jiàn)。在我之前使用開(kāi)源的renren-fast-vue中這種手法更是大量運(yùn)用,這次學(xué)習(xí)d2-admin也借鑒一下這種全局變量的使用(掛載變量一時(shí)爽,一直掛載一直爽,小心別翻車(chē)了)。先不管了,一頓Copy操作猛如虎,定睛一看,注釋占了百分之九十五!當(dāng)然,代碼了瞬間有了后端的痕跡,不過(guò)在本項(xiàng)目 public/index.html中使用的模板語(yǔ)法來(lái)源于 lodash 模板插入,和public文件夾相關(guān)的內(nèi)容可以去翻翻d2-admin文檔關(guān)于cli 和 webpack 配置部分,這里就不再贅述,總之,萬(wàn)丈高樓平地起,基礎(chǔ)建設(shè)很重要!
全局配置window.SITE_CONFIG
window.SITE_CONFIG = {}; window.SITE_CONFIG["version"] = "<%= process.env.VUE_APP_VERSION %>"; // 版本 window.SITE_CONFIG["nodeEnv"] = "<%= process.env.VUE_APP_NODE_ENV %>"; // node env window.SITE_CONFIG["apiURL"] = "<%= process.env.VUE_APP_API %>"; // api請(qǐng)求地址 window.SITE_CONFIG["storeState"] = {}; // vuex本地儲(chǔ)存初始化狀態(tài)(用于不刷新頁(yè)面的情況下,也能重置初始化項(xiàng)目中所有狀態(tài)) window.SITE_CONFIG["contentTabDefault"] = { // 內(nèi)容標(biāo)簽頁(yè)默認(rèn)屬性對(duì)象 "name": "", // 名稱(chēng), 由 this.$route.name 自動(dòng)賦值(默認(rèn),名稱(chēng) === 路由名稱(chēng) === 路由路徑) "params": {}, // 參數(shù), 由 this.$route.params 自動(dòng)賦值 "query": {}, // 查詢參數(shù), 由 this.$route.query 自動(dòng)賦值 "menuId": "", // 菜單id(用于選中側(cè)邊欄菜單,與this.$store.state.sidebarMenuActiveName進(jìn)行匹配) "title": "", // 標(biāo)題 "isTab": true, // 是否通過(guò)tab展示內(nèi)容");
大廠某H5案例中全局配置掛載
前端輕量級(jí)web進(jìn)度條-NProgress
感覺(jué)像我這種資深Copy級(jí)別的零級(jí)工程師,對(duì)于一些炫酷的頁(yè)面效果,除了感嘆"牛掰",就是一頓復(fù)制粘貼。當(dāng)我看到d2-admin使用的NProgress是0.2.0版本的時(shí)候,我以為是個(gè)比較新的第三方庫(kù),抱著刨根到底的學(xué)習(xí)心態(tài),我點(diǎn)開(kāi)了NProgress的github倉(cāng)庫(kù),看到作者@rstacruz的主頁(yè),不禁贊嘆:"牛掰!"。說(shuō)來(lái)也巧,@justjavac 大神翻譯的速查表就源自作者的cheatsheets。雖然NProgress誕生于2013年8月,(那時(shí)我還在學(xué)校把妹,對(duì)js的了解還只是不小心按到F12),@rstacruz對(duì)她的維護(hù)長(zhǎng)達(dá)5年之久,目前有18.8K的star,而@rstacruz本尊更是值得我輩瞻仰的大神。
來(lái)看看NProgress怎么使用:一行代碼實(shí)現(xiàn)web進(jìn)度條。
//... import NProgress from "nprogress" import "nprogress/nprogress.css" //... NProgress.start() //... NProgress.done()
NProgress的實(shí)現(xiàn)原理也很好理解,源碼比較簡(jiǎn)潔,大概是加載開(kāi)始調(diào)用start,加載完成調(diào)用done,至于加載進(jìn)度、具體加載到哪了,都不關(guān)心,中間狀態(tài)是隨機(jī)的進(jìn)度,從源碼中看到大概加載到99.4%的位置就停了。
NProgress核心源碼
NProgress.inc = function(amount) { var n = NProgress.status; if (!n) { return NProgress.start(); } else if(n > 1) { return; } else { if (typeof amount !== "number") { if (n >= 0 && n < 0.2) { amount = 0.1; } else if (n >= 0.2 && n < 0.5) { amount = 0.04; } else if (n >= 0.5 && n < 0.8) { amount = 0.02; } else if (n >= 0.8 && n < 0.99) { amount = 0.005; } else { amount = 0; } } n = clamp(n + amount, 0, 0.994); return NProgress.set(n); } }; //... /** * Helpers */ function clamp(n, min, max) { if (n < min) return min; if (n > max) return max; return n; }
感興趣的同學(xué)可以看看源碼學(xué)習(xí)學(xué)習(xí)!?nprogress.js
iframe的支持
在d2-admin中,其實(shí)是有實(shí)現(xiàn)iframe類(lèi)型的內(nèi)容頁(yè)組件的-- d2-container-frame,從源碼來(lái)看,是iframe是嵌套在d2-container組件中的,利用絕對(duì)定位實(shí)現(xiàn)iframe充滿d2-container盒子。
d2-container-frame簡(jiǎn)單實(shí)現(xiàn)
在改造renren的項(xiàng)目中,大佬巧妙的利用組裝route的方式,實(shí)現(xiàn)了iframe多帶帶渲染,具體可以看下源碼:?支持 iframe 加載方式:
// ... // 組裝路由 var route = { path: "", component: null, name: "", meta: { ...window.SITE_CONFIG["contentTabDefault"], menuId: menuList[i].id, title: menuList[i].name } } // ... route["path"] = route["name"] = `i-${menuList[i].id}` route["meta"]["iframeURL"] = URL route["component"] = { render (h) { return h("d2-container", {}, [ h("iframe", { style: { position: "absolute", top: "0px", left: "0px", height: "100%", width: "100%" }, attrs: { src: URL, frameborder: 0 } }) ]) } } // ...
后記
源碼雖然沒(méi)有細(xì)看,不過(guò)還是根據(jù)commits提交記錄,粗略的一步一步copy實(shí)現(xiàn)了一番。整個(gè)過(guò)程還是很有趣的,畢竟算是參與了開(kāi)源,還給大佬提了issue,捉了bug。但是,總得來(lái)說(shuō),還有很多知識(shí)點(diǎn)沒(méi)細(xì)看,如vue的mixins、眾多頁(yè)面的具體實(shí)現(xiàn)、iconfont的使用、Vuex的使用、自定義皮膚的實(shí)現(xiàn)、頂部菜單欄的實(shí)現(xiàn)等等,期間也遇到一些編譯上的問(wèn)題,如el-table的坑?Error: if there"s nested data, rowKey is required.。感覺(jué)整個(gè)過(guò)程還學(xué)的不踏實(shí),很多知識(shí)點(diǎn)只是一搜帶過(guò),可能還是項(xiàng)目做少了。路漫漫其修遠(yuǎn),慢慢摸索吧。 HR的領(lǐng)導(dǎo)來(lái)電話催回家了,匆匆落筆,結(jié)束此篇,江湖再見(jiàn)!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/6691.html
摘要:介于目前項(xiàng)目的前端開(kāi)發(fā)基于人人企業(yè)版有了快狗團(tuán)隊(duì)的手摸手,很快就能用部署這樣一個(gè)后臺(tái)管理平臺(tái)。構(gòu)建鏡像,部署靜態(tài)資源這里借助獲取鏡像,通鏡像作為基礎(chǔ)來(lái)構(gòu)建人人企業(yè)版鏡像。本許可協(xié)議授權(quán)之外的使用權(quán)限可以從處獲得。 Created by huqi at 2019-5-24 21:01:30 Updated by huqi at 2019-5-26 00:00:42 前言 最近后端的小...
摘要:介于目前項(xiàng)目的前端開(kāi)發(fā)基于人人企業(yè)版有了快狗團(tuán)隊(duì)的手摸手,很快就能用部署這樣一個(gè)后臺(tái)管理平臺(tái)。構(gòu)建鏡像,部署靜態(tài)資源這里借助獲取鏡像,通鏡像作為基礎(chǔ)來(lái)構(gòu)建人人企業(yè)版鏡像。本許可協(xié)議授權(quán)之外的使用權(quán)限可以從處獲得。 Created by huqi at 2019-5-24 21:01:30 Updated by huqi at 2019-5-26 00:00:42 前言 最近后端的小...
摘要:數(shù)人云容器助力產(chǎn)品迭代力沙龍干貨分享實(shí)錄持續(xù)上新,今天是來(lái)自人人貸高級(jí)運(yùn)維工程師杜天鵬的分享,與我們細(xì)數(shù)了人人貸容器化實(shí)踐過(guò)程中遇到的問(wèn)題以及解決方法。 數(shù)人云容器助力產(chǎn)品迭代力MAX沙龍干貨分享實(shí)錄持續(xù)上新,今天是來(lái)自人人貸高級(jí)運(yùn)維工程師杜天鵬的分享,與我們細(xì)數(shù)了人人貸容器化實(shí)踐過(guò)程中遇到的問(wèn)題以及解決方法。 很高興站在這里和大家一起交流容器技術(shù),我叫杜天鵬,是人人貸的運(yùn)維工程師。人...
摘要:公司項(xiàng)目需要用到繪圖框架,繪圖部分以前是另一位同事負(fù)責(zé),用的是框架。基于以上提及到的種種原因,上年年末我做起了技術(shù)調(diào)研,希望能找到一個(gè)合適我們項(xiàng)目的繪圖框架。兼容性問(wèn)題項(xiàng)目對(duì)瀏覽器兼容性比較寬松,瀏覽器兼容性問(wèn)題不在考慮范圍之內(nèi)。 showImg(https://ws3.sinaimg.cn/large/006tKfTcgy1g0ppk2kkhxj30ka0b4gm5.jpg); 公司...
閱讀 3690·2021-09-07 10:19
閱讀 3633·2021-09-03 10:42
閱讀 3588·2021-09-03 10:28
閱讀 2555·2019-08-29 14:11
閱讀 814·2019-08-29 13:54
閱讀 1600·2019-08-29 12:14
閱讀 421·2019-08-26 12:12
閱讀 3619·2019-08-26 10:45