抱歉生病拖更了,1024快乐javascript
上回还真的有同窗提到了这个问题,感谢细心的你。@_noobcss
实际上是没任何问题的,只不过看起来违背了常见的结构,像是有问题。实际上是上文为了照顾初学者,怕你们由于麻烦而放弃,并无一次性改的“看起来那么复杂”,咱们来填下坑。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项目》准备 - 前端了解过关了吗?前端基础架构和技术介绍