摘要:輸入框內容過濾產品有一個需求是,在搜索用戶信息時,只能通過郵箱搜索,并且只能輸入字母數字以及。我選擇了輸入框的值這里的坑就是需要在中更新值,因為元素這時才刷新。是否有一定要用的必要類似的管理系統涉及到不同頁面之間的交互都很少。
初始化項目
使用 Vue-cli3 初始化項目1
安裝 Element UI
安裝 Vue-i18n,做相關配置2,3
原則上需要對 Element 也做 I18n 的處理,但是我覺得 Element 中已經有很完善的多語言翻譯,而 Element 自身尚不支持 Vue-i18n 7+ 版本,要特殊處理,所以就算了,這里直接使用了 Element 自帶的方法。項目結構
. |-- babel.config.js |-- package.json |-- public | `-- index.html |-- src | |-- App.vue | |-- assets | | |-- override-element-ui.less // 覆蓋 Element 默認樣式 | | `-- image // 圖片文件目錄 | |-- components // 所有非 `Element 按需加載` 中顯示的頁面的 Vue 組件 | | |-- mainMenu.vue // 左側導航 | | |-- pureTitle.vue // 通用的 Title 組件,項目中有多個頁面會用到 | | |-- search.vue // 通用的 Search 頭部組件,同樣會用到 | | `-- userCenter.vue // 字面意思用戶中心,目前只需要顯示用戶名,handle 用戶退出操作。可預見:下拉菜單操作、頭像顯示等... | |-- main.js // Vue-cli 生成的項目基本文件 | |-- router.js // Vue-cli 生成,路由 | |-- store // Vuex相關 | | |-- index.js | | |-- mutationTypes.js | | `-- module // 這里按照路由劃分了 module,不一定對 | | | |-- someModule.js | | | `-- elseModule.js | |-- utils | | |-- i18n // 國際化支持 | | | |-- index.js | | | `-- lang // 語言字符串文件 | | | |-- en.json | | | `-- zh.json | | |-- request // 處理所有 ajax 請求 | | | |-- index.js // 基于 axios,封裝了需要用到的方法,例如 token 的處理 | | | |-- someComponentName.js // 基于組件分割的請求,在 Vuex action 中調用獨立方法 | | | `-- elseComponentName.js | | |-- timeHelper.js // 時間戳轉換幫助函數 | | `-- userHelper.js // 保存用戶信息幫助函數 | `-- views // ` 下內容顯示組件` | |-- Home.vue | |-- Login.vue | |-- MainPage.vue | |-- Manage.vue | `-- Verify.vue |-- .env.development // 環境變量 process.env |-- .env.production // 生產環境下的環境變量 `-- vue.config.js // 更改 Vue-cli 默認配置
先看一張項目初始狀態下,全局引入 Element & 按需引入打包大小的對比:
How參考:按需引入
需要注意的地方是:
不用新建 .babelrc 文件,只需要更改 babel.config.js
使用 Vue-cli 初始化項目后, presets 中為 ["@vue/app"],不需要更改為 element 官網中的 es2015 。原因是 babel 的目前版本已經不推薦按照 JavaScript 版本來區分編譯目標。(// todo:添加相關鏈接)
可用的 babel.config.js 文件如下:
module.exports = { presets: [ ["@vue/app"], ], plugins: [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] }覆蓋默認樣式
正常情況下,可以通過直接修改對應 class 的內容修改。但含有 foo__bar 類似格式的樣式不會應用 scoped(因為不是同一個 Vue 實例),因此修改不會生效。
可以通過在 *.vue 中不使用 scope 來解決這個問題,Element 在 Issue 中也吐槽過。雖然我不認為 scope 不是一個好的解決方案。
因此,我選擇了在 main.js 中引入外部樣式表,例如override-element-ui.less,在外部樣式表中修改 foo__bar 類名的樣式。
路由設計route.js 主要設計如下:
routes: [ { path: "/login", name: "login", component: Login }, { path: "/", name: "home", component: Home, children: [ { path: "/index", component: mainPage }, { path: "/manage", component: manage, children: [ { path: "user/:uumsid&:userid", component: userDetail }, { path: "enterprise/:id", component: insDetail }, { path: "/", component: manageList }, ] }, { path: "/verify", component: Verify, }, { path: "/verify/:id", component: VerifyDetail }, { path: "*", redirect: "/index" }, ] }, ]
555...不太想貼代碼,感覺太亂、太長。
但不貼又說不清楚。
簡單來說,項目只分為兩個部分。登陸頁和功能頁。
根路由綁定到了登陸后的首頁。
首頁包含頭部標題、左側菜單還有顯示內容的
因此,如果用戶僅輸入 location.host 訪問網站,會被帶到 ${host}/index 頁面。另外,訪問任意未被匹配的 path,都會重定向到 index 頁面。
這個時候會出現兩個分支:
判斷本地是否存在用戶信息是否存在 ? 進行正常操作 :重定向到登錄頁
如何保存用戶信息和登陸狀態整個系統只需要分成需要登錄和不需登陸兩個部分。
當前所開發的系統除登錄頁外,都需要登錄后訪問。
這個部分和路由設計強相關。何時判斷用戶是否登錄在上一部分已經解釋過。
使用 localstorage 來持久化保存用戶信息,處理用戶刷新頁面以及一段時間內關閉瀏覽器后不用重新登錄的需求。(一段時間為30min)
在 Home.vue 的 created() 鉤子中做如下操作:
created() { let userInfo = getUserFromLocal("userinfo") let verifiedUserInfo = (info) => { let now = new Date().getTime() const PASS_TIME = 1000 * 60 * 30 // 30min if (!info) return false if (now - info.time < PASS_TIME) return true return false } if (!!verifiedUserInfo(userInfo)) { this.onRefresh(userInfo) } else { this.$router.push({path: "/login"}) } }
其中,getUserFromLocal 是在 userHelper.js 中寫的從 localstorage 中獲取數據的方法。通過判斷用戶信息是否存在以及是否過期來決定是跳轉到登錄頁還是直接使用當前已有的用戶信息。
// 我不覺得這是一個很完美的方案,但根據我搜索的資料來看,確實沒有詳細說過這方面內容的文章。所以,期待能看到更好的方案。
如何優雅的觸發表單驗證Element 的表單驗證方法
但沒有給出 async-validator 支持的表單驗證觸發方式。
經過查找,支持的觸發方式有: submit, blur, input
我選擇的方案是在規則中使用 submit 時驗證(指表單提交時觸發,因此實際情況中永遠不會觸發,但能滿足需求,即手動觸發驗證。)
同時,在點擊登錄或者發送請求按鈕時,調用 this.$refs.[formEl].validate((boolean) => { // callback})
清除表單驗證結果:
當表單項很多時,也可以在中調用clearValidate(prop), prop 指表單項的 name 值。
輸入框內容過濾產品有一個需求是,在搜索用戶信息時,只能通過郵箱搜索,并且只能輸入字母、數字以及@。因此,我們需要對用戶輸入數據時即時進行過濾。(別問我為什么不在用戶輸入完成后提示錯誤,這是需求。
我選擇了 watch 輸入框 value 的值:
value(val) { this.$nextTick(() => { this.value = this.reg ? val.replace(this.reg, "") : val }) }
這里的坑就是需要在 $nextTick() 中更新 value 值,因為 DOM 元素這時才刷新。
這個需求有許多 blog 都給出過不同的解決方案,可以多看看選擇一下。
獲取數據時的細節問題 ajax 的封裝基于 axios
./utils/request/index.js:
import axios from "axios" // BASE_HOST 通過 .env.[development|production] 配置。注意:每個變量都要用 VUE_APP作為前綴,否則不能識別 const BASE_HOST = process.env.VUE_APP_API_BASE const TIME_OUT = 1000 * 10 /** * * @param URL {string} * @param params {Object} */ export function POST(URL, params) { if (!URL.includes(BASE_HOST)) URL = BASE_HOST + URL return axios({ method: "post", url: URL, data: params, timeout: TIME_OUT }) } export function GET(URL, data) { // like POST } /** * @param URL {string} * @param token {string} * @param params {Object} */ export function GET_WITH_TOKEN(URL, token, params) { if (!URL.includes(BASE_HOST)) URL = BASE_HOST + URL return GET(URL, { params, headers: { token: token }, timeout: TIME_OUT }) }
封裝了基本的 GET,POST等方法,沒想到什么特別的作用,也沒有想到不好的地方,留著為了以防萬一。(事實上,也用上了。比如超時處理。但是,超時處理在下一層也能做。但這樣的話登陸就需要多帶帶設置超時了。)
GET_WITH_TOKEN(以及 POST_WITH_TOKEN 等) 用于需要登錄鑒權的接口
顯示 Loading 狀態在等待api返回數據時可以用loading告訴用戶頁面正在加載。Element 提供的 Loading組件
一般切換路由后,會在組件的 created() 方法中發送請求。這種情況下應該在 nextTick()(或者mounted()中) 中調用 loading ,避免頁面切換時找不到 DOM,出現全屏 loading 或頁面閃爍。
尚不明確(梗I18n 的方案不夠完善,現在做到了語言文件的熱切換,但是對業務來講似乎沒有什么必要。沒有做語言字符串的按需加載(事實上是做了但沒有實現),但這個似乎比熱切更重要一點。
按照 Vue-router 實現了懶加載及文件命名,但瀏覽器似乎仍然會下載所有 JS 文件,在 JS Tab 中可以看到只下載了當前頁用到的文件。
Vuex 是否有一定要用的必要?類似的管理系統涉及到不同頁面之間的交互都很少。在該系統中完全沒有,雖然有不同組件的交互,但都能較簡單的把狀態提升到其父組件。因此,Vuex 唯一必須要用的理由就是保存用戶狀態。因為登陸后的接口都需要 token 校驗,保存在 Vuex 中可以非常方便的使用。
參考資料Vue CLI 3
Vue I18n
如何讓一個vue項目支持多語言(vue-i18n)
同步在博客:https://blog.life1st.me/artic...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98131.html
摘要:利用中間件實現異步請求,實現兩個用戶角色實時通信。目前還未深入了解的一些概念。往后會寫更多的前后臺聯通的項目。刪除分組會連同組內的所有圖片一起刪除。算是對自己上次用寫后臺的一個強化,項目文章在這里。后來一直沒動,前些日子才把后續的完善。 歡迎訪問我的個人網站:http://www.neroht.com/? 剛學vue和react時,利用業余時間寫的關于這兩個框架的訓練,都相對簡單,有的...
摘要:用來主要前臺的請求,并處理返回相關的數據,做后臺服務。總結做完這個項目,其中的過程還是挺艱辛的,畢竟都是邊學邊做,不過最后能完成還是挺開心的,終于有了一個從到的項目過程。雖然只是一個小小的練手項目,不過對于目前的我,感覺還是不錯的。 showImg(https://oc1gyfe6q.qnssl.com/17-3-30/43434844-file_1490879850754_14751...
摘要:用來主要前臺的請求,并處理返回相關的數據,做后臺服務??偨Y做完這個項目,其中的過程還是挺艱辛的,畢竟都是邊學邊做,不過最后能完成還是挺開心的,終于有了一個從到的項目過程。雖然只是一個小小的練手項目,不過對于目前的我,感覺還是不錯的。 showImg(https://oc1gyfe6q.qnssl.com/17-3-30/43434844-file_1490879850754_14751...
摘要:用來主要前臺的請求,并處理返回相關的數據,做后臺服務??偨Y做完這個項目,其中的過程還是挺艱辛的,畢竟都是邊學邊做,不過最后能完成還是挺開心的,終于有了一個從到的項目過程。雖然只是一個小小的練手項目,不過對于目前的我,感覺還是不錯的。 showImg(https://oc1gyfe6q.qnssl.com/17-3-30/43434844-file_1490879850754_14751...
閱讀 3072·2021-10-11 10:58
閱讀 1989·2021-09-24 09:47
閱讀 502·2019-08-30 14:19
閱讀 1684·2019-08-30 13:58
閱讀 1444·2019-08-29 15:26
閱讀 640·2019-08-26 13:45
閱讀 2139·2019-08-26 11:53
閱讀 1772·2019-08-26 11:30