国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

記一次開源學習--D2Admin 人人企業版

notebin / 3329人閱讀

摘要:前言上個月月底開源組開源了使用適配人人企業版專業版的前端工程具體詳情見人人企業版適配發布。當然,也督促自己產出一篇相關的文章,來記錄這次有趣的學習之旅。

Created by huqi at 2019-5-5 13:01:14
Updated by huqi at 2019-5-20 15:57:37

前言

上個月月底@D2開源組 開源了使用 D2Admin 適配 人人企業版(專業版) 的前端工程--d2-admin-renren-security-enterprise,具體詳情見?D2Admin 人人企業版適配發布。由于最近有開發后臺管理系統的需求,加上其他諸多因素,如:想學習優秀的開源項目、剛好參加@jsliang 組織的暴走前端、之前項目使用過renren-fast-vue等等,于是乎萌生了根據commits學習了解d2-admin如何改造renren-security前端的想法。當然,也督促自己產出一篇相關的文章,來記錄這次有趣的學習之旅。

前置準備

所謂“工欲善其事必先利其器”,連我這樣的Copy攻城獅都要搭建的前端基礎開發環境,都9102年啦,再沒有node環境都沒法進行前端開發了,再不濟運行d2-admin的環境總該有吧!

安裝環境
這里請參考D2 Admin快速上手部分:?安裝環境

Fork D2-Admin@1.6.18
這里緊跟@FairyEver 大大的思路,基于D2-Admin@1.6.18 開發。當然也可以通過D2 Admin CLI來初始化項目,具體操作參照:?下載項目

了解D2Admin項目結構
有過開發經歷的同學在項目開發之前一般都有過項目結構搭建的經歷,當然如果您不幸和我一樣只會用別人搭建好的工程腳手架,那您一定會先了解整個項目目錄結構,不然還真不知道源碼要寫在哪里。

項目結構

├─ docs // 文檔 ├─ packages // 額外的包 ├─ public // 公共文件 ├─ src // 源碼目錄 │ ├─ assets // 資源 │ │ ├─ icons │ │ ├─ image │ │ ├─ library │ │ └─ style │ ├─ components // 組件 │ │ ├─ charts │ │ ├─ core │ │ └─ demo │ ├─ i18n // 多語言 │ ├─ menu // 菜單 │ ├─ mock // 模擬數據 │ ├─ pages // 頁面 │ ├─ plugin // 插件 │ ├─ router // 路由 │ ├─ store // vuex │ ├─ utils │ ├─ App.vue │ └─ main.js ├─ tests // 測試文件 ├─ .browserslistrc // 瀏覽器兼容設置 ├─ .env // 環境變量 ├─ .env.development // 開發環境變量 ├─ .env.nomock // nomock環境變量 ├─ .env.travis // 生成環境變量 ├─ .eslintignore // ESLint忽略 ├─ .eslintrc.js // ESLint配置 ├─ .gitignore // git忽略 ├─ .postcssrc.js // postcss配置 ├─ .travis.yml // 持續集成服務 ├─ babel.config.js // babel配置 ├─ cdnrefresh-dirs.txt // cdn設置 ├─ jest.config.js // jest設置 ├─ LICENSE // 開源協議 ├─ package-lock.json // 包文件鎖版本 ├─ package.json // 包文件 ├─ qiniu-config // 七牛云配置 ├─ qshell // 七牛API服務命令行工具 ├─ README.md |— README.zh.md ├─ vue.config.js // vue配置

刪除無關文件
刪除.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/*。具體可查看:?刪除暫時未用到模塊

修改package.json
移除暫時未用到的包,如多語言,這個版本將簡化多語言目錄結構,如圖表庫、富文本編輯、右鍵菜單等:
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命令,增加環境變量文件.env、.env.production、.env.production.sit、.env.production.uat等。至此,可以通過npm installyarn來安裝項目依賴,并通過npm run dev之類的指令運行項目,具體指令可查看 package.json 文件中 scripts 部分。

重寫國際化

至于為什么要重寫,要問大佬了。我也只能妄加揣測:簡化結構!之前的結構是一個index.js+lang文件夾,lang文件夾里又包含多個語言文件夾,現在的結構直接了當--index.js+多個語言js文件。關于國際化我也只是很膚淺的了解,雖然之前接觸過的項目也做過,里邊坑的確挺多的,除了基本的翻譯還要結合當地的文化習俗,這里就不展開討論,搜索關鍵字i18n便有眾多的解決方案?;氐酱罄蠤FairyEver 的源碼,跟著他了解一下vue-i18n的使用:

安裝依賴

npm install vue-i18n

main.js中引入

// ... // i18n import i18n from "@/i18n" // ... new Vue({ i18n, // ... )}

新建語言包,構建js
核心代碼:

index.js

// 引入相關依賴及語言包 import Vue from "vue" import VueI18n from "vue-i18n" import Cookies from "js-cookie" // 附帶引入element-ui的多語言切換 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" // 引入語言包 import zhCN from "./zh-CN" import zhTW from "./zh-TW" import enUS from "./en-US" Vue.use(VueI18n) // 定義使用的語言 export const messages = { "zh-CN": { "_lang": "簡體中文", ...zhCN, ...zhCNLocale }, "zh-TW": { "_lang": "繁體中文", ...zhTW, ...zhTWLocale }, "en-US": { "_lang": "English", ...enUS, ...enLocale } } // 默認從cookie中讀取或設置為中文 export default new VueI18n({ locale: Cookies.get("language") || "zh-CN", messages })

語言包以灣灣繁體為例:

zh-TW.js

// 定義語言對象 const t = {} t.loading = "加載中..." // 構建對象 t.brand = {} t.brand.lg = "人人權限企業版" t.brand.mini = "人人" // ... export default t

使用

App.vue

// 選擇語言 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 // 非登錄頁面,切換語言刷新頁面 if (this.$route.name !== "login" && oldVal) { window.location.reload() } } } }

頁面中使用,如:

// template {{ $t("login.motto.text") }} :placeholder="$t("login.form.placeholderUsername")" // script this.$t("login.motto.text")

檢驗成果
實踐是檢驗真理的唯一標準。 修改i18n/index.js 將locale改為灣灣繁體,就能直觀的看到title的變化,(別問我為啥頁面上的文字怎么沒變化?因為寫死為簡體中文啦?。?/p>

注意: 實現vue-i18n+element-ui多語言切換需手動注冊如,參考element-ui國際化:

// 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) })

文字部分全部修改為國際化后,就可以看到明顯的效果啦:

多語言切換

既然有了國際化的基礎,那么實現一個多語言切換的小功能應該是水到渠成。來看看@FairyEver是怎么教的! 偶然間看到d2-admin中的標簽可以使用flex這個屬性,感到很好奇。

flex,對于新世紀的前端開發來說最熟悉不過,但是標簽上直接寫flex屬性,作為很水很水的老菜鳥卻是孤落寡聞,不過職業病的直覺告訴我一定是跟flex布局有關。于是我按圖索驥,先翻閱了一下package.json,里邊果然找到一個flex.css的依賴包。大概實現怎樣的效果呢?我的認知是通過標簽的flex屬性,無需寫css即可實現flex布局,flex.css內部通過定義屬性選擇器樣式來實現flex布局,更多關于flex.css請戳?flex.cc。

這里通過elemen-ui的el-dropdown實現,通過command事件修改語言設置

{{ language.label }}

對接人人驗證碼

一般來說,做登錄頁的時候,我們或多或少會遇到驗證碼的需求,對了,這里的驗證碼指的是圖形驗證碼。最簡單的實踐是直接拿后臺給過來的圖片直接渲染的在頁面上,使用 img標簽 或者 background-image 引入。之前做renren-fast-vue二次開發的時候用的img標簽,這里用的背景圖片,思路都一樣:拿后臺給的圖片直接渲染。眾所周知,Just do it!

定義獲取uuid的工具函數:

/** * @description [ renren ] 獲取uuid */ util.getUUID = function () { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => { return (c === "x" ");

使用uuid獲取圖形驗證碼

// 選擇語言 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 // 非登錄頁面,切換語言刷新頁面 if (this.$route.name !== "login" && oldVal) { window.location.reload() } } } }

axios及登錄邏輯

自從擺脫了JQuery大法,阿賈克斯和我從此是陌生人,以至于面試官要我闡述阿賈克斯原理,我真是啞巴吃黃連,哦不,是啞口無言,一個以CP(Copy&Paste)為生的搬磚工,你們還指望他侃侃而談什么原理什么底層?至于什么axios攔截,總之,這一塊涉及到前后交互的知識點還是蠻多的,我也是七竅通靈六竅--一竅不通,勉勉強強解讀一下大佬的封裝:

axios簡單封裝

// 引用相關依賴及方法 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" // 記錄和顯示錯誤 function errorLog (error) { // 添加到日志 store.dispatch("d2admin/log/push", { message: "數據請求異常", type: "danger", meta: { error } }) // 打印到控制臺 if (process.env.NODE_ENV === "development") { // util.log.danger(">>>>>> Error >>>>>>") console.log(error) } // 顯示提示 Message({ message: error.message, type: "error", duration: 5 * 1000 }) } // 創建一個 axios 實例 const service = axios.create({ baseURL: process.env.VUE_APP_API, timeout: 1000 * 180, // 請求超時時間 withCredentials: true // 當前請求為跨域類型時是否在請求中協帶cookie }) /** * 請求攔截 */ service.interceptors.request.use( config => { // 在請求發送之前做一些處理,如設置headers config.headers["Accept-Language"] = Cookies.get("language") || "zh-CN" config.headers["token"] = Cookies.get("token") || "" // 默認參數 var defaults = {} // 防止緩存,GET請求默認帶_t參數 if (config.method === "get") { config.params = { ...config.params, ...{ "_t": new Date().getTime() } } } if (isPlainObject(config.data)) { // 純粹對象解構賦值 config.data = { ...defaults, ...config.data } if (/^application/x-www-form-urlencoded/.test(config.headers["content-type"])) { // 序列化請求數據 config.data = qs.stringify(config.data) } } return config }, error => { // 發送失敗 console.log(error) return Promise.reject(error) } ) /** * 響應攔截 */ service.interceptors.response.use( response => { // 處理響應 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

登錄的話,需要調用api,按照d2-admin的項目結構,在src/api下定義api接口,如sys.login.js:

import request from "@/plugin/axios" export function login (data) { return request({ url: "/login", method: "post", data }) }

調用api進行登錄:

// ... 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) }) } // ...

當然還需要對數據進行處理,比如登錄狀態持久化、設置vuex用戶信息等等,這里暫時只做簡單的處理,另外安利一個vscode插件(乳溝您恰巧用的宇宙第一神器)--TODO Highlight,用來突出顯示代碼中的todo、fixme和其他注釋,聽說老司機都在用。有時,在將代碼發布到生產環境之前,在編碼時忘記查看添加的TODO。所以就有了這個拓展,提醒我們有一些筆記或者事情還沒有完成。mark一下!

標準化cookie使用

作為后臺管理系統,免不了涉及到cookie的使用,按照大佬的思路,定義了工具集函數并基于js-cookie二次封裝了cookie。一般來說,cookie用得最多的就是get和set兩個方法。

cookie簡單封裝

import Cookie from "js-cookie" /** * @description 存儲 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}`) }

如圖,能看到目前通過此次標準化封裝之后存的cookie的name都加了**d2admin-**的前綴。

防止過度點擊

節流這個知識點我也是一直懵懵懂懂,經常和防抖混淆,理解不深刻,還只是停留在字面意思理解上:函數節流是指定時間間隔內只執行一次,函數防抖是頻繁觸發只有間隔超過指定時間間隔才執行。請參考debouncing-throttling-explained-examples 這里簡單粗暴的用了lodash--一個一致性、模塊化、高性能的 JavaScript 實用工具庫。。 lodash中包含一系列數組、數字、對象、字符串等操作的API,當然還有一些常用的工具函數如節流(throttle)、防抖(debounce)。

// ... import { debounce } from "lodash" // ... submit: debounce(function () { // ... }, 1000, { "leading": true, "trailing": false }) // _.debounce(func, [wait=0], [options={}]) // options.leading 與|或 options.trailing 決定延遲前后是先調用后等待,還是先等待后調用 // ...

前后對比:
未處理的時候,觸發的請求令人發指!

處理之后,控制臺讓人感覺很清爽

關于全局配置

項目做得太少了,尤其還不會java,對網站的全局配置這一塊的理解還停留在初級認知階段。一般來說,在網頁開發中往往一些版本控制、CDN靜態資源、api接口地址、常用的公共變量等都會寫到window下面并提升至首頁方便管理,如網易一些爆款的H5中這種手法非常常見。在我之前使用開源的renren-fast-vue中這種手法更是大量運用,這次學習d2-admin也借鑒一下這種全局變量的使用(掛載變量一時爽,一直掛載一直爽,小心別翻車了)。先不管了,一頓Copy操作猛如虎,定睛一看,注釋占了百分之九十五!當然,代碼了瞬間有了后端的痕跡,不過在本項目 public/index.html中使用的模板語法來源于 lodash 模板插入,和public文件夾相關的內容可以去翻翻d2-admin文檔關于cli 和 webpack 配置部分,這里就不再贅述,總之,萬丈高樓平地起,基礎建設很重要!

全局配置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請求地址 window.SITE_CONFIG["storeState"] = {}; // vuex本地儲存初始化狀態(用于不刷新頁面的情況下,也能重置初始化項目中所有狀態) window.SITE_CONFIG["contentTabDefault"] = { // 內容標簽頁默認屬性對象 "name": "", // 名稱, 由 this.$route.name 自動賦值(默認,名稱 === 路由名稱 === 路由路徑) "params": {}, // 參數, 由 this.$route.params 自動賦值 "query": {}, // 查詢參數, 由 this.$route.query 自動賦值 "menuId": "", // 菜單id(用于選中側邊欄菜單,與this.$store.state.sidebarMenuActiveName進行匹配) "title": "", // 標題 "isTab": true, // 是否通過tab展示內容");

大廠某H5案例中全局配置掛載

前端輕量級web進度條-NProgress

感覺像我這種資深Copy級別的零級工程師,對于一些炫酷的頁面效果,除了感嘆"牛掰",就是一頓復制粘貼。當我看到d2-admin使用的NProgress是0.2.0版本的時候,我以為是個比較新的第三方庫,抱著刨根到底的學習心態,我點開了NProgress的github倉庫,看到作者@rstacruz的主頁,不禁贊嘆:"牛掰!"。說來也巧,@justjavac 大神翻譯的速查表就源自作者的cheatsheets。雖然NProgress誕生于2013年8月,(那時我還在學校把妹,對js的了解還只是不小心按到F12),@rstacruz對她的維護長達5年之久,目前有18.8K的star,而@rstacruz本尊更是值得我輩瞻仰的大神。

來看看NProgress怎么使用:一行代碼實現web進度條。

//... import NProgress from "nprogress" import "nprogress/nprogress.css" //... NProgress.start() //... NProgress.done()

NProgress的實現原理也很好理解,源碼比較簡潔,大概是加載開始調用start,加載完成調用done,至于加載進度、具體加載到哪了,都不關心,中間狀態是隨機的進度,從源碼中看到大概加載到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; }

感興趣的同學可以看看源碼學習學習!?nprogress.js

iframe的支持

在d2-admin中,其實是有實現iframe類型的內容頁組件的-- d2-container-frame,從源碼來看,是iframe是嵌套在d2-container組件中的,利用絕對定位實現iframe充滿d2-container盒子。

d2-container-frame簡單實現