vue总结

Vue项目总结

Vue项目基本使用

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调用

子组件传递给父组件

子组件:

<template>

    <div @click="up"></div>

</template>

 

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:

<template>
    <div>
        <p>the count of d is{{fooCount}}</p>
        <button @click="addBar" >foo</button>
    </div>
</template>
<script>
    import Bus from './bus'
    export default{
        data(){
            return{
                fooCount:0
            }
        },
        methods:{
            addBar(){
                this.fooCount++
                Bus.$emit('addBar',this.fooCount)
            }
        }
    }
</script>
 
3.然后bar组件里通过$on(name,callback)里获取到foo组件发送的内容,name表示foo组件发送的信息名字,callback表示一个回调函数,来执行获取信息后的一些操作,代码如下,导入bus.js:
<template>
    <div>
        <p>the count of d is{{barCount}}</p>
    </div>
</template>
<script>
import Bus from './bus'
    export default{
        data(){
            return{
                barCount:0
            }
        },
        created(){
            Bus.$on('addBar',(arg)=>{
                this.barCount=arg
            })
        }
    }
</script>
 
 

可以实现非父子组件的通信,但是存在一个问题,

问题一:就是在路由切换的时候,并不触发bus.$on

事件

方案一:使用sessionStorage在路由切换的时候改变缓存的值,即可解决

问题二:多次切换路由,bus.$on监听事件在不断增加,事件实行每切换一次就增加一次

原因:你的 bus是全局的,在整个页面的生命周期里面的,然后切换路由的时候,component 的生命周期其实是控制不到你 bus的,也就是销毁不了这个事件,可以在componentbeforeDestory或者是destory事件中,也就是在组件销毁的时候手动执行下bus.$off("change_app_charts"),手动销毁事件

解决方案一:监听事件:Bus.$on('search', this.searchArticle)
需要在当前组件添加beforeDestroy() {
  Bus.$off('search', this.searchArticle);
},

给input框添加enter键

<el-input type="password"v-model="loginForm.password" placeholder="密码"@keyup.enter.native="loginSubmit"></el-input>
@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')

从本地json获取数据


在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 => {})
 

 

 

Vue识别html标签的办法

<p v-html="txt.head1.p1"></p>

使用v-html识别

 

Vuex状态管理

简单使用

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">inc</button>
  </div>
  </template>
  
  <script>
  
  
  export default {
    methods: {
      inc () {
        this.$store.commit('inc')
      },
      dec () {
        this.$store.commit('dec')
      }
    }
  }
  </script>

 

 

就可以实现多个组件同时操作数据

项目遇到的问题

npm run dev的问题

项目部署,需要将config中build的assetsPublicPath: './',而dev中的assetsPublicPath不可设置为'./',否则用npm run dev会cannot get的错误,必须将dev中的assetsPublicPath不可设置为'/'

vue-resource与axios请求区别


  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= [

 
{
    path: '/',
   
component:Layout,
   
redirect: '/index'
 
},
];
export const adminRouterMap= [
 
{
    path: '/limitManage',
   
component: Layout,
   
name:'权限管理',
   
redirect: 'noredirect',
   
children: [
     
{path: 'user', component: User,name:'用户管理'},
     
{path: 'role', component: Role,name:'角色管理'}
   
]
  },
]

export default new Router({
 
routes: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){
 
router.addRoutes(adminRouterMap)
}
else{
 
console.log(router)
}

 
}
 
 
}
 
4.   这样会有一个问题:就是当角色为管理员的时候,切换至地方站,直接输入管理员权限网址还是能够被打开
5.   解决方案:就是当登录成功之后跳转页面后刷新页面一次

6.   this.$router.push('/index')
window.location.reload();

 
 

成功实现后台权限的问题


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值