抱歉生病拖更了,1024快樂javascript
上回還真的有同窗提到了這個問題,感謝細心的你。@_noob
css
實際上是沒任何問題的,只不過看起來違背了常見的結構,像是有問題。實際上是上文爲了照顧初學者,怕你們由於麻煩而放棄,並無一次性改的「看起來那麼複雜」,咱們來填下坑。html
爲了照顧沒有實時跟着我連載的同窗,每一章的代碼單獨發佈在個人 Github 博客,不進行覆蓋更新 [除非代碼有錯誤進行修改],這樣避免了 2019 年小明同窗望着前兩章和 Github 最終版本代碼發呆 ( release 也不是特別友好)
咱們把上文的 renderer/src 改爲比較容易理解的 src/renderer ,這實際上是一個編程習慣問題。前端
上文 renderer/src 的問題vue
eslint-config-alloy : 想寫出更規範的代碼能夠參考這個規則java
下面進入本章正題node
使用了 vue 的你,發現 Vue 竟然不能發請求,因而你 Google 了下,發現能夠用 Vue-Resource。
你去問別人 Vue-Resource 怎麼樣,他說不要用 Vue-Resource,由於 Vue-Resource 官方已經中止維護了,你應該用 Axios、或者 fetch。可是咱們想擁抱 ES6 排除掉了 ES5的fetch(固然也有ES6-fetch),這裏咱們使用 Axios!python
這裏呢也科普一下:何時依賴須要放到 dependencies、何時依賴須要放到 devDependencies:webpack
devDependencies:顧名思義,僅在開發(dev)模式下如:webpack. 、.loader、eslint、babel、打包後部署時徹底用不到的、僅在開發須要 編譯、檢測、轉換 的放在這裏。
dependencies:例如:axios、chart、js-cookie、less、lodash、underscore等運行時的庫或工具類等相關依賴咱們要放在這裏
不過基本不用擔憂,官網都會提供 start 說明,可是咱們要大概明白意思,不要機械般的 copy。ios
2018-09-28 截圖 npmjs.com
"dependencies": { "axios": "^0.18.0" }
基於上一章內容,別忘了從新 npm i 下載一下
還記得咱們自動生成的 vue 主頁面腳本 main.js嗎?
咱們在 src/renderer/utils
創建一個 request.js
在這個請求腳本中,對 Axios 作一些必要的封裝,大概內容是用 攔截器 axios.interceptors 對請求和響應作些攔截,定義一下 API 的前綴,處理一些常見的 HTTP 狀態碼。
我儘量的爲你們寫了詳細的註釋。
// src/renderer/utils/request.js import axios from 'axios' //這裏通常指後端項目API的前綴,例如 /baidu/*/*/1.api /mi/*/*/2.api const BASE_API = "" export function axiosIntercept(Vue, router) { const axiosIntercept = axios.create({ baseURL: BASE_API }) //http request 攔截器 通常用來在請求前塞一些全局的配置、或開啓一些 css 加載動畫 axios.interceptors.request.use( (config) => { // 判斷是否存在token,若是存在的話,則每一個http header都加上token // if (store.getters.accessToken) { // console.log(store.getters.accessToken) // config.headers.Authorization = `token ${store.getters.accessToken}`; // } //todo:加載動畫 //如有需求能夠處理一下 post 亦或改變post傳輸格式 if (config.method === 'post') { }; return config; }, function (err) { return Promise.reject(err); }); //http response 攔截器 通常用來根據一些後端協議特殊返回值作一些處理,例如:權限方面、404... 或關閉一些 css 加載動畫 axiosIntercept.interceptors.response.use(function (response) { // todo: 暫停加載動畫 return response; }, function (err) { //捕獲異常 if (err.response) { switch (err.response.status) { case 401: // do something 這裏咱們寫完後端作好約束再完善 } } return Promise.reject(err); }); return axiosIntercept; }
你們還記得咱們用 vue-cli 生成的 vue 主頁腳本 main.js 吧,這裏咱們須要對 Axios 和 Vue 作一個耦合。
// src/renderer/main.js import axios from 'axios' import { axiosIntercept } from './utils/request' // 將Axios擴展到Vue原型鏈中 Vue.prototype.$http = axiosIntercept(Vue)
這樣咱們在寫業務邏輯,直接在 Vue 的上下文中 使用 this.$http 來發送請求。既實現了攔截、又實現了狀態的共享。
知其然,知其因此然
節省代碼量,讓代碼更加易讀
擴展到原型鏈,使 Axios 運行時共享 Vue 原型鏈的內容,減小了不少指代 Vue 的臨時變量
傳統狀況
import axios from 'axios' new Vue({ data: { user: "" }, created: function () { //此時做用域在 Vue 上,緩存起來,要依賴此變量 let _this = this; axios.get("/user/getUserInfo/" + userName).then(res => { if (res.data.code === 200) { //此時做用域在axios上,拿不到vue綁定的值,只能藉助剛纔緩存的_this上下文 _this.data.user = res.data.user } }); } })
代理以後
new Vue({ data: { user: "" }, created: function () { // axios 成爲了 vue 的原型鏈一部分,共享vue狀態。 this.$http.get("/user/getUserInfo/" + userName).then(res => { if (res.data.code === 200) { //注意,axios回調,應該儘可能使用箭頭函數,能夠繼承父類上下文,不然相似閉包,仍是沒法共享變量、 // 更優雅了一些 this.data.user = res.data.user } }); } })
不懂 prototype 能夠翻翻我之前寫的文章
先簡單弄一下,爲先後分離打個小鋪墊
resolve: { extensions: ['.js', '.vue', '.json'], alias: { '@': resolve('src/renderer'), } },
爲了使用起來更加優雅,能夠爲每一個經常使用的目錄都創建別名
resolve: { extensions: ['.js', '.vue', '.json'], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src/renderer'), 'assets': resolve('src/renderer/assets'), 'components': resolve('src/renderer/components'), 'container': resolve('src/renderer/container'), 'utils': resolve('src/renderer/utils') } },
dev 是開發時啓動的指令
build 是預發佈時 webPack 打包的指令
假設筆者只是一個前端,一般呢,在開發調試過程中,沒法避免須要與後端的同窗進行 API 的對接,那也就不免會出現跨域問題。固然傳統 javaWeb 不須要跨域,(ip 域 端口 任何一個不一樣皆爲跨域) 在 DEV 模式調試中,咱們都是儘可能選擇前端環境規避跨域問題,而不會去額外搭建 nginx 或更改後端代碼。
跨域只是針對 JavaScript 的,由於開發者認爲瀏覽器上的腳本是不安全的。
既然咱們的 vue 項目是 node 全家桶,依靠 node、webPack 編譯 咱們直接配置 node 的 proxyTable 做爲開發的代理器,這樣最簡單,依次配置,團隊受益。
https://cnodejs.org/api
上邊cnode 的 API 是能夠隨意調用的,由於後端作了處理。
看看掘金的:
https://xiaoce-timeline-api-m...
請求一下,不出意外瀏覽器作了跨域報警。
哦,咱們適配一下 node 代理
官方例子在這:
https://vuejs-templates.githu...
擴展一下 proxyTable:
proxyTable: [{ //攔截全部v1開頭的xhr請求 context: ['/v1'], target: "https://xiaoce-timeline-api-ms.juejin.im", cookieDomainRewrite: { // 不用cookie }, changeOrigin: true,//重點,此處本地就會虛擬一個服務替咱們接受或轉發請求 secure: false }],
再次發送請求。
這樣,先後分離的項目能夠這樣藉助 swagger 測試接口,不須要騷擾任何人。實現本身的業務邏輯,簡單實現一點。
代碼:
// blog/index.vue <template> <div class="Blog"> <h1>{{ msg }}</h1> <div v-for="(blog,index) in blogList" v-bind:key="index"> <h3 > <a :href="`https://juejin.im/book/`+blog.id" > <span>{{blog.title}}</span> </a> </h3> </div> </div> </template> <script> export default { name: "Blog", data() { return { msg: "掘金小冊一覽", blogList: [] }; }, created() { this.getBlog(); }, methods: { getBlog() { this.$http.get("/v1/getListByLastTime?src=web&pageNum=1").then(res => { this.blogList = res.data.d; }); } } }; </script>
寫完代碼以後部署到線上,是不會在線上 clone 代碼以後 Npm run dev 的😆,那樣會有太多太多的垃圾依賴,爲用戶帶來了災難性的網絡請求,一般藉助webPack打包以後發佈到服務器的web服務當中。
運行
npm run build
打包目錄是以前配置的webpack
好了,不少人直接雙擊 index.html 是不行的。
Tip: built files are meant to be served over an HTTP server.
Opening index.html over file:// won't work.
須要 http 服務啓動,能夠扔到本地或服務器的 nginx、apache、tomcat等容器測試,我一般使用 python 啓動一個 http 服務來運行(腳本地址)、固然,本身 ide 支持 http 啓動也能夠。
生產當中,由於前端後端必然不一樣端口,避免跨域,一般使用 nginx 的正向/反向代理做爲跨域的手段。(並不是負載均衡,兩個概念)
server { listen 80; server_name localhost; location ^~ /v1 { proxy_pass https://xiaoce-timeline-api-ms.juejin.im;#代理。 proxy_set_header X-Real-IP $remote_addr;#轉發客戶端真實IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } }
簡單配置一下就能夠了,很少講,前端同窗瞭解一下就能夠了,nginx 能幹的事情還有不少。
你是否爲了找某一個業務的接口頭痛
你是否還在使用全局搜索找本身的接口
你是否某一個接口不一樣組件重複寫了屢次
整理一下本身的接口吧,像上文的 router 同樣整齊的劃分吧。
/renderer 下創建一個 api 的文件夾
webpack.base.conf.js 添加一條 api 的別名,方便咱們往後大量調用
'api': resolve('src/renderer/api')
咱們創建 /renderer/api/juejin.js
import axios from 'axios' let Api = Function() Api.prototype = { getBlog(page, fn) { axios.get(`/v1/getListByLastTime?src=web&pageNum=${page}`).then(res => { // if (res.data.code === 200) { fn(res.data) // } }).error() } } export default new Api()
修改一下咱們剛纔 /blog/index.vue 的 Axios 請求:
import juejin from "@/api/juejin";
注掉以前離散的 axios ,使用從 api 中定義過的 XHR 請求數據。
getBlog() { // this.$http.get("/v1/getListByLastTime?src=web&pageNum=1").then(res => { // this.blogList = res.data.d; // }); juejin.getBlog("1", response => { this.blogList = response.d; }); }
OK,不少同窗不理解,原本簡單的事情爲何搞複雜了?其實這樣不復雜,看起來還很清晰,假若一個大項目上千個請求,不只重複致使代碼覆蓋率低,看起來還很亂,不利於團隊協做。本系列文章在帶領你們先後分離的基礎上,會爲你們提供更多有利於團隊的開發方式,養成良好習慣。
《從零構建先後分離web項目》:開篇 - 縱觀WEB歷史演變
《從零構建先後分離web項目》探究 - 深刻聊聊先後分離架構
《從零構建先後分離web項目》準備 - 前端了解過關了嗎?前端基礎架構和技術介紹