Open jackieli123723 opened 6 years ago
记录一些使用 vue-cli 脚手架创建项目时,遇到的一些问题以及解决方案
如果你的后端 API 服务是 Express 提供或者是 Thinkjs 再或者是 koa2 等等,当你请求数据时就会面临着跨域请求问题
执行 npm run dev,你会发现会报一个错误:vue-resource.common.js?e289:1071 POST http://localhost:8080/api/use... 404 (Not Found)。这是由于直接访问 8080 端口,是访问不到的,所以这里需要设置一下代理转发映射.
npm run dev
vue-resource.common.js?e289:1071 POST http://localhost:8080/api/use... 404 (Not Found)
8080
项目根目录下的 config 文件夹中有一个 proxyTable 参数,用来设置地址映射表,可以添加到开发时配置(dev)中
|-- config |-- dev.env.js |-- index.js |-- prod.env.js
dev: { // ... proxyTable: { '/api': { target: 'http://127.0.0.1:3000/api/', changeOrigin: true, pathRewrite: { '^/api': '' } } }, // ... }
添加以上代码之后,请求 /api 时就代表 http://127.0.0.1:3000/api/(这里要写 ip,不要写 localhost), changeOrigin 参数接收一个布尔值,如果为 true,这样就不会有跨域问题了。
/api
http://127.0.0.1:3000/api/
更多接口参数配置,请参考 https://github.com/chimurai/http-proxy-middleware#options
webpack 接口配置文档 https://webpack.js.org/configuration/dev-server/#devserver-proxy
|-- src |-- axios |-- index.js |-- config.js
正式上线时,不推荐使用上一个方案,这里推荐使用 axios 进行转发
export default { serverUrl: 'http://127.0.0.1:3000/' }
import axios from 'axios' import config from '@/config' // 设置全局 axio s默认值 axios.defaults.baseURL = config.serverUrl axios.defaults.timeout = 5000 // 5000的超时验证 axios.defaults.headers.post['Content-Type'] = 'application/jsoncharset=UTF-8' // 创建一个 axios 实例 const instance = axios.create() instance.defaults.headers.post['Content-Type'] = 'application/jsoncharset=UTF-8' axios.interceptors.request.use = instance.interceptors.request.use export async function postDate (username, password) { try { const response = await fetch.post('/postDate', { username, password }) return response.data } catch (err) { console.log('message', err) if (err.response) { throw Error(err.response.data.message) } throw err } }
|-- src |-- components |-- HerderBar.vue |-- FooterBar.vue |-- pages |-- Home.vue
假如你的 components 目录下有 HerderBar.vue 和 FooterBar.vue 这两个子组件,而 Home.vue 要引用这两组件,那么下面这种写法可以完成该需求
<template> <div> <header-bar></header-bar> <!-- ... ... --> <footer-bar></footer-bar> </div> </template> <script> import HeaderBar from '@/components/HeaderBar' import FooterBar from '@/components/FooterBar' export default { name: 'Home', components: { HeaderBar, FooterBar } } </script>
市面上用的比较广泛的图标库有两个,一是阿里巴巴矢量图标库,其有上百万图标共程序员选择,自定义比较强;二是Font Awesome,该图标库虽没有上百万图标,但也受到大部门程序员喜爱。
很多人在写 Vue 项目时,前端 UI 框架都喜欢使用 Element UI,但是该 UI 框架默认提供的图标库实现是少之又少,但是该 UI 框架允许我们引入第三方图标库
这个引入就非常简单了,在 iconfont 网站上有提供离线版和在线版,看自己的意愿,然后在 index.html 里使用 style 标签引入即可。
参考代码element-font-awesome
使用 less 时,别忘了安装 npm 依赖
npm install -S less less-loader
|-- src |-- font.less |-- main.js
import './font.less'
[class^="el-icon-fa"], [class*=" el-icon-fa"] { display: inline-block; font: normal normal normal 14px/1 FontAwesome!important; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }; @import url("../node_modules/font-awesome/less/font-awesome"); @fa-css-prefix: el-icon-fa;
对于 css 的预编译器,个人比较喜欢 sass 的,在使用 sass 时仍然需要添加 npm 依赖
npm install --save node-sass sass-lodaer
|-- src |-- assets |-- scss |-- _public.scss |-- index.scss |-- App.vue
<style lang="scss"> @import './assets/scss/index'; </style> <template> <div id="app"> </div> </template> <script> export default { name: 'app' } </script>
@import 'public';
#app { font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
|-- src |-- store |-- modules |-- ... ... |-- actions.js # 根级别的 action => |-- getters.js # 根级别的 mutation => |-- index.js # 我们组装模块并导出 store 的地方 |-- types.js # 根级别的 type => 状态 |-- main.js
import Vue from 'vue' import App from './App' import store from './store' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', store, template: '<App/>', components: { App } })
|-- router |-- axios |-- index.js |-- main.js
import Vue from 'vue' import App from './App' import router from './router' Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, template: '<App/>', components: { App } })
下面这一代码片段是使用 vue-cli 下载的模板写法,但是这种写法会使你的 URL 变成 http://localhost:8080/#/
vue-cli
http://localhost:8080/#/
import Vue from 'vue' import Router from 'vue-router' // ... ... Vue.use(Router) export default new Router({ routes: [ { path: '/', // ... ... } ] })
对于强迫症的人来说,这样的 URL 非常丑,这就需要开启 HTML5 History 模式,更具体的说明请看官方文档 vue-router HTML5 History 模式
HTML5 History
import Vue from 'vue' import Router from 'vue-router' // ... ... Vue.use(Router) const router = new VueRouter({ mode: 'history', routes: [ { path: '/', // ... ... } ] }) export default router
对于进入某些页面需要进行登录验证,那么就需要设置路由拦截,vue-router 官方文档称之为导航钩子,具体请看官方文档 vue-router 导航钩子
vue-router
实际上在进行路由拦截时需要进行数据验证,当验证通过时方能允许其通过该路由,该验证数据通常会存储在 vuex 的 state 中,或者会存储在 Local Storage,再或者 Session Storage,无论存储在哪里,vue-router 配置文件能够正确访问到即可,当然验证程序就需要后端服务 API 提供了
vuex
state
Local Storage
Session Storage
import Vue from 'vue' import Router from 'vue-router' import store from '@/store' // ... ... Vue.use(Router) const router = new VueRouter({ mode: 'history', routes: [ { path: '/', // ... ... meta: { requireAuth: true // 添加该字段,表示进入这个路由是需要进行验证的 } } ] }) router.beforeEach((to, from, next) => { if (to.matched.some(r => r.meta.requireAuth)) { // 判断该路由是否需要登录权限 if (store.state.token) { // 通过 vuex state 获取当前的 token 是否存在 next() } else { next({ path: '/login', // 验证失败,将会跳转到该路由 query: { redirect: to.fullPath } // 将跳转的路由 path 作为参数,登录成功后跳转到该路由 }) } } else { next() } }) export default router
自从 Vue.js 更新至 2.x 版本之后,官方就不再使用 vue-resource,替而代之的是 axios
vue-resource
|-- src |-- axios |-- index.js |-- pages |-- Home.vue |-- main.js
import Vue from 'vue' import App from './App' import api from './axios' Vue.prototype.$api = api Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', template: '<App/>', components: { App } })
使用 vue-router 进行路由拦截是不够的,当然也是需要数据验证的,更加详细的说明以及例子请移步 【vue+axios】一个项目学会前端实现登录拦截
import axios from 'axios' import store from '../store' import router from '../router' // 设置全局axios默认值 axios.defaults.timeout = 5000 // 5000的超时验证 axios.defaults.headers.post['Content-Type'] = 'application/jsoncharset=UTF-8' // 创建一个axios实例 const instance = axios.create() instance.defaults.headers.post['Content-Type'] = 'application/jsoncharset=UTF-8' axios.interceptors.request.use = instance.interceptors.request.use // http request 拦截器 instance.interceptors.request.use( config => { if (store.state.token) { config.headers.Authorization = `token ${store.state.token}`.replace(/(^")|("$)/g, '') } return config }, error => { return Promise.reject(error) }) // http response 拦截器 instance.interceptors.response.use( response => { return response }, error => { if (error.response) { switch (error.response.status) { case 401: store.dispatch('UserLogout') router.replace({ path: 'login', query: { redirect: router.currentRoute.fullPath } }) } } return Promise.reject(error.response) }) export default { // POST PostData (data) { return instance.post('/api/postData', data) }, // GET GetData () { return instance.get('/api/user/getData') } }
<template> <div> <!-- ... ... --> </div> </template> <script> export default { name: 'Home', data: { return { fromData: [ // ... ... ] } }, created () { this.$api.GetData() .then(({data}) => { // ... ... }) .catch((err) => { console.log(err) }) }, methods: { post () { const opt = this.fromData this.$api.PostData(opt) .then(({data}) => { // ... ... }) .catch((err) => { console.log(err) }) } } } </script>
记录一些使用 vue-cli 脚手架创建项目时,遇到的一些问题以及解决方案
设置代理与跨域
开发时设置
如果你的后端 API 服务是 Express 提供或者是 Thinkjs 再或者是 koa2 等等,当你请求数据时就会面临着跨域请求问题
执行
npm run dev
,你会发现会报一个错误:vue-resource.common.js?e289:1071 POST http://localhost:8080/api/use... 404 (Not Found)
。这是由于直接访问8080
端口,是访问不到的,所以这里需要设置一下代理转发映射.项目根目录下的 config 文件夹中有一个 proxyTable 参数,用来设置地址映射表,可以添加到开发时配置(dev)中
config/index.js
添加以上代码之后,请求
/api
时就代表http://127.0.0.1:3000/api/
(这里要写 ip,不要写 localhost), changeOrigin 参数接收一个布尔值,如果为 true,这样就不会有跨域问题了。更多接口参数配置,请参考 https://github.com/chimurai/http-proxy-middleware#options
webpack 接口配置文档 https://webpack.js.org/configuration/dev-server/#devserver-proxy
正式上线时设置
正式上线时,不推荐使用上一个方案,这里推荐使用 axios 进行转发
src/config.js
src/axios/index.js
父子组件
假如你的 components 目录下有 HerderBar.vue 和 FooterBar.vue 这两个子组件,而 Home.vue 要引用这两组件,那么下面这种写法可以完成该需求
src/pages/Home.vue
图标库
市面上用的比较广泛的图标库有两个,一是阿里巴巴矢量图标库,其有上百万图标共程序员选择,自定义比较强;二是Font Awesome,该图标库虽没有上百万图标,但也受到大部门程序员喜爱。
很多人在写 Vue 项目时,前端 UI 框架都喜欢使用 Element UI,但是该 UI 框架默认提供的图标库实现是少之又少,但是该 UI 框架允许我们引入第三方图标库
iconfont
这个引入就非常简单了,在 iconfont 网站上有提供离线版和在线版,看自己的意愿,然后在 index.html 里使用 style 标签引入即可。
fontawesome
参考代码element-font-awesome
使用 less 时,别忘了安装 npm 依赖
目录结构
src/main.js
src/font.less
sass
对于 css 的预编译器,个人比较喜欢 sass 的,在使用 sass 时仍然需要添加 npm 依赖
目录结构
src/App.vue
src/assets/scss/index.scss
src/assets/scss/public.scss
vuex
目录结构
src/main.js
vue-router
目录结构
src/main.js
HTML5 History 模式
下面这一代码片段是使用
vue-cli
下载的模板写法,但是这种写法会使你的 URL 变成http://localhost:8080/#/
对于强迫症的人来说,这样的 URL 非常丑,这就需要开启
HTML5 History
模式,更具体的说明请看官方文档 vue-router HTML5 History 模式router/index.js
路由拦截
对于进入某些页面需要进行登录验证,那么就需要设置路由拦截,
vue-router
官方文档称之为导航钩子,具体请看官方文档 vue-router 导航钩子实际上在进行路由拦截时需要进行数据验证,当验证通过时方能允许其通过该路由,该验证数据通常会存储在
vuex
的state
中,或者会存储在Local Storage
,再或者Session Storage
,无论存储在哪里,vue-router
配置文件能够正确访问到即可,当然验证程序就需要后端服务 API 提供了router/index.js
axios
自从 Vue.js 更新至 2.x 版本之后,官方就不再使用
vue-resource
,替而代之的是 axios目录结构
src/main.js
axios 拦截
使用 vue-router 进行路由拦截是不够的,当然也是需要数据验证的,更加详细的说明以及例子请移步 【vue+axios】一个项目学会前端实现登录拦截
axios/index.js
在 Vue 组件内调用
src/pages/Home.vue