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();

 
 

成功實現後臺權限的問題


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章