Vue项目总结
1. 安装node,使用node –v检测node版本
2. 使用npm install vue安装vue
3. 全局安装vue-cli,npm install vue-cli –g
4. 使用vue init webpack my-project
5. cd my-project
6. npm install
7. npm run dev
进入了vue的欢迎页面
├── build // 构建相关
├── config // 配置相关
├── src // 源代码
│ ├── assets // 主题 字体等静态资源
│ ├── styles // 全局样式
│ ├── js // 全局js
│ ├── img // 图片
│ ├── components // 全局公用组件
│ ├── router // 路由
│ ├── store // 全局store管理
│ ├── view // view
│ ├── App.vue // 入口页面
│ └── main.js // 入口 加载组件 初始化等
├── static // 第三方不打包资源
│ └── Tinymce // 富文本
├── .babelrc // babel-loader 配置
├── eslintrc.js // eslint 配置项
├── .gitignore // git 忽略项
├── favicon.ico // favicon图标
├── index.html // html模板
└── package.json //package.json
newwebpack.ProvidePlugin({
$: 'jquery' ,
'jQuery': 'jquery'
})
Vue-cli默认只提供dev和prod两种环境,但真正开发流程可能还会多一个测试环境check,需要做相应设置
1. 需要在packjson中增加
"build:check": "node build/check.js" |
2. 需要新建check.js,webpack.check.conf.js和config中创建check.env.js
复制build.js到check.js做相应修改
增加:var config = require('../config') var config = require('../config') 修改:var config = require('../config') var webpackConfig=require('./webpack.check.conf') rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory) rm(path.join(config.check.assetsRoot, config.check.assetsSubDirectory) |
3. webpack.conf.js修改
var env = process.env.NODE_ENV === 'testing' ? require('../config/test.env') : config.check.env 将其他的build都改为check |
4. check-versions.js修改
exports.assetsPath = function (_path) { var assetsSubDirectory = process.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.check.assetsSubDirectory return path.posix.join(assetsSubDirectory, _path) }
5. utils。Js做相同修改
6. check.env.js
module.exports = { NODE_ENV: '"production"', API_ROOT: '"http://test.internal.auto.ifeng.com/automedia/api/media"' }
7. 在index中将build复制一份修改成check
1、mainjs引入importtuantype from './components/common/tuantype.vue'
2、注册Vue.component('tuantype',tuantype)
3、实例化
components: {
'tuantype': tuantype
}
4、使用
父组件数据如何传递给子组件呢?可以通过props属性来实现
父组件
<parent> <child :child-msg="msg"></child>//这里必须要用 - 代替驼峰 </parent>
data(){ return { msg: [1,2,3] }; } |
子组件通过props来接收数据:
props: { childMsg: { type: Array, default: [0,0,0] //这样可以指定默认的值 } } |
子组件调用方式:1.在标签内使用{{clildMsg}}调用
2.在方法中可以使用this.childMsg调用
子组件:
<div @click="up">div>
methods: { up() { this.$emit('upup','hehe'); //主动触发upup方法,'hehe'为向父组件传递的数据 } } |
父组件:
<div> <child @upup="change":msg="msg">child> //监听子组件触发的upup事件,然后调用change方法 div> methods: { change(msg) { this.msg = msg; } } |
1.创建一个bus.js
import Vue from 'vue'
export default new Vue();
|
2.在父组件中定义后这两个组件
相应的,foo组件是通过$emit(name,val)方法将信息发送出去,name表示发送信息的名字,val表示发送的内容,导入bus.js:
|
3.然后bar组件里通过$on(name,callback)里获取到foo组件发送的内容,name表示foo组件发送的信息名字,callback表示一个回调函数,来执行获取信息后的一些操作,代码如下,导入bus.js:
|
可以实现非父子组件的通信,但是存在一个问题,
问题一:就是在路由切换的时候,并不触发bus.$on
事件
方案一:使用sessionStorage在路由切换的时候改变缓存的值,即可解决
问题二:多次切换路由,bus.$on监听事件在不断增加,事件实行每切换一次就增加一次
原因:你的 bus
是全局的,在整个页面的生命周期里面的,然后切换路由的时候,component
的生命周期其实是控制不到你 bus
的,也就是销毁不了这个事件,可以在component
的beforeDestory
或者是destory
事件中,也就是在组件销毁的时候手动执行下bus.$off("change_app_charts")
,手动销毁事件
解决方案一:监听事件:Bus.$on('search', this.searchArticle)
需要在当前组件添加beforeDestroy() { Bus.$off('search', this.searchArticle); },
@keyup.enter.native="loginSubmit"
this.$router.push('/autoMedia/wxAccount')
1、安装两个依赖 npm install -S file-saver xlsx npm install -D script-loader 2、导入两个文件vendor->Blob.js,vendor->Export2Excel.js(vendor随意起) 3、 require.ensure([], () => { const {export_json_to_excel} = require('../../vendor/Export2Excel') const tHeader = ['品牌', '团购数量', '报名人数', '成交数量', '团购数量占比', '报名人数占比', '成交数量占比'] const filterVal = ['brandName', 'grouponCount', 'signCount', 'arrivedCount', 'doneCount', 'arrivedRatio', 'doneRatio'] const list = this.saletableData const data = this.formatJson(filterVal, list) export_json_to_excel(tHeader, data, '用户信息列表') }) } formatJson: function (filterVal, jsonData) { return jsonData.map(v => filterVal.map(j => v[j])) } 4、如果webpack报解析错误: 在build----webpack.base.conf.js中resolve的alias加入 'vendor': path.resolve(__dirname, '../src/vendor')
在build->dev-server.js中添加下边内容:
//定义路由
var apiRoute = express.Router();
apiRoute.get('/localData',function(req, res){
res.json({
errno:0,//错误码
data: localData//具体数据
})
})
//注册定义的api
app.use('/api',apiRoute);
调用方式:this.$http.get(‘/api/localData’).then(res => {})
<p v-html="txt.head1.p1">p>
使用v-html识别
1. 在main.js中添加
const store = new Vuex.Store({ state: { count: 0 }, mutations: { inc: state => state.count++, dec: state => state.count-- } })
|
2. 在组件中添加
<template> <div> {{ $store.state.count}} <button @click="inc">incbutton> div> template> <script> export default { methods: { inc () { this.$store.commit('inc') }, dec () { this.$store.commit('dec') } } } script>
|
就可以实现多个组件同时操作数据
项目部署,需要将config中build的assetsPublicPath: './',而dev中的assetsPublicPath不可设置为'./',否则用npm run dev会cannot get的错误,必须将dev中的assetsPublicPath不可设置为'/'
2.1get请求区别,vue-resouce的get请求
this.$http.get(this.url + '/captcha', {emulateJSON: true}).then(function (res) { this.login.authcode = res.body.data.captchaImage this.sessionId = res.body.data.sessionId }) axios的 this.$http.get(this.url + '/captcha', {emulateJSON: true}).then(response => { this.login.authcode = response.data.data.captchaImage this.sessionId = response.data.data.sessionId }) |
1.2 post请求区别 axios可以直接跨域,但是axios的post的请求必须是使用qs模块
import qs from 'qs'; this.$http.post(this.url + '/login', qs.stringify({ account: this.login.username, password: this.login.password, checkcode: this.login.captcha, sessionId: this.sessionId }), {emulateJSON: true}).then(response => {}) |
项目中跨域问题比较常见,在vue中的跨域方式一般使用cors跨域来实现
1. 对于vue-resource的跨域问题解决方案:增加请求头实现跨域
this.$http.post(url,{emulateJSON: true}, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}}).then(function (res) {})
|
2.对于axios不需要添加请求有就可以实现跨域
3.在本地设置代理函数
在config的index。Js中的的dev中做如下修改
proxyTable: { '/api': { target: 'http://test.internal.auto.ifeng.com/automedia/api/media', changeOrigin: true, pathRewrite: { //需要rewrite重写的, 如果在服务器端做了处理则可以不要这段 '^/api': '' } } },
|
直接请求api就可以实现请求代理,没有跨域问题
需求:在任何一个页面任何一次http请求,增加对token过期的判断,如果token已过期,需要跳转至登录页面。如果要在每个页面中的http请求操作中添加一次判断,那么会是一个非常大的修改工作量。那么vue-resource是否存在一个对于任何一次请求响应捕获的的公共回调函数呢?答案是有的!
下边代码添加在main.js中
Vue.http.interceptors.push((request, next) => { console.log(this)//此处this为请求所在页面的Vue实例 // modify request request.method = 'POST';//在请求之前可以进行一些预处理和配置 // continue to next interceptor next((response) => {//在响应之后传给then之前对response进行修改和逻辑判断。对于token时候已过期的判断,就添加在此处,页面中任何一次http请求都会先调用此处方法 response.body = '...'; return response; }); });
|
Axios拦截器:
// http request 拦截器 axios.interceptors.request.use( config => { if (store.state.token) { // 判断是否存在token,如果存在的话,则每个http header都加上token config.headers.Authorization = `token ${store.state.token}`; } return config; }, err => { return Promise.reject(err); });
// http response 拦截器 axios.interceptors.response.use( response => { return response; }, error => { if (error.response) { switch (error.response.status) { case401: // 返回 401 清除token信息并跳转到登录页面 store.commit(types.LOGOUT); router.replace({ path: 'login', query: {redirect: router.currentRoute.fullPath} }) } } return Promise.reject(error.response.data) // 返回接口返回的错误信息 }); |
需求:左菜单被选中后再次刷新希望目录再次显示到当前目录
解决问题:element-ui的框架
<el-menu router :default-active="$route.path" >
|
使默认选中为当前路由,不管在任何地方改变路由,左菜单都会跟着变化
1. 实现理论:前端会有一份路由表,它表示了每一个路由可访问的权限。当用户登录之后,通过token获取用户的role,动态根据用户的role算出其相应有权限的路由,再通过router.addRoutes动态挂载路由。但这些控制都只是页面级的,说白了前端再怎么做权限控制都不是绝对安全的,后端的权限验证是逃不掉的。
2. 解决办法:权限是有后端返回配置路由,这样其实很痛苦
3. 前端自己实现权限问题,易于管理,但是需要完成后端的思想逻辑
自己的实现方式:
1. 实现思路:控制左边次侧边栏导航和实现动态路由
左侧边栏使用:用v-if去判断是否有这样的一个权限
<el-submenu index="2" v-if="this.getUserobj&&this.getUserobj.roleArea==0"> <template slot="title" class="nav-title"><img src="//p1.ifengimg.com/auto/image/2017/0625/auth.png" alt="权限管理" class="tit_icon">权限管理 template> <el-menu-item index="/limitManage/user" style="padding-left:48px;height:40px;line-height:40px;min-width:100px;"> 用户管理 el-menu-item> <el-menu-item index="/limitManage/role" style="padding-left:48px;height:40px;line-height:40px;min-width:100px;"> 角色管理 el-menu-item> el-submenu>
2. 改变路由
3. export const constRouterMap= [
|
默认的是不需要权限的路由
3,在main.js中引入
import router from './router/index' import { adminRouterMap, constRouterMap } from '@/router'
引入后再
router.beforeEach((to, from, next) => { if (getUserobj && getUserobj.token) { if(getUserobj.roleArea==0){ } } |
4. 这样会有一个问题:就是当角色为管理员的时候,切换至地方站,直接输入管理员权限网址还是能够被打开
5. 解决方案:就是当登录成功之后跳转页面后刷新页面一次
6. this.$router.push('/index') |
成功实现后台权限的问题