Vue搭建後臺項目

參考:javascript

https://github.com/PanJiaChen/vue-element-admin/blob/master/README.zh-CN.mdcss

http://www.javashuo.com/article/p-hdwsabyi-ct.htmlhtml

一、當項目逐漸變大以後,文件與文件直接的引用關係會很複雜,這時候就須要使用alias了。前端

//webpack.base.config.js
alias: {
  'src': path.resolve(__dirname, '../src'),
  'components': path.resolve(__dirname, '../src/components'),
  'api': path.resolve(__dirname, '../src/api'),
  'utils': path.resolve(__dirname, '../src/utils'),
  'store': path.resolve(__dirname, '../src/store'),
  'router': path.resolve(__dirname, '../src/router')
}

//使用xxx.js
import stickTop from 'components/stickTop'
import getArticle from 'api/article'

二、ESLintvue

 不論是多人合做仍是我的項目,代碼規範是很重要的。這樣作不只能夠很大程度地避免基本語法錯誤,也保證了代碼的可讀性。推薦 eslint+vscode 來寫 vue。java

每次保存,vscode就能標紅不符合eslint規則的地方,同時還會作一些簡單的自我修正。安裝步驟以下:node

1)首先在vscode裏安裝eslint插件react

2)點擊 文件 > 首選項 > 設置 打開 VSCode 配置文件,添加以下配置。這樣每次保存的時候就能夠根據根目錄下.eslintrc.js你配置的eslint規則來檢查和作一些簡單的fix。webpack

{
  "files.autoSave":"off",
  "eslint.validate": [
      "javascript",
      "javascriptreact",
      "html",
      { "language": "vue", "autoFix": true }
    ],
    "eslint.options": {
      "plugins": ["html"]
  },
  "eslint.autoFixOnSave": true
}

三、js環境變量ios

process對象是 Node 的一個全局對象,提供當前 Node 進程的信息。它能夠在腳本的任意位置使用,沒必要經過require命令加載。process.env屬性返回一個對象,包含了當前Shell的全部環境變量一般的作法是,新建一個環境變量NODE_ENV,用它肯定當前所處的開發階段,生產階段設爲production,開發階段設爲developstaging,而後在腳本中讀取process.env.NODE_ENV便可

DefinePlugin:容許你建立一個在編譯時能夠配置的全局常量。這可能會對開發模式和發佈模式的構建容許不一樣的行爲很是有用。

//webpack.prod.conf.js
var env = process.env.NODE_ENV === 'production' ? config.build.prodEnv : config.build.sitEnv
new webpack.DefinePlugin({
  'process.env': env
})
//package.json
"scripts": {
  "dev": "node build/dev-server.js",
  "build:prod": "cross-env NODE_ENV=production node build/build.js",
  "build:sit": "cross-env NODE_ENV=sit node build/build.js"
}

cross-env這個npm包使得在使用或設置環境變量時能用同一種方式適配不一樣的平臺(以unix方式設置環境變量,而後在windows上也能兼容運行)

三、先後端交互

1)封裝 axios

//request.js
import axios from 'axios'
import { Indicator, MessageBox } from 'mint-ui'

// 建立axios實例
const service = axios.create({
  baseURL: process.env.BASE_API, // api的base_url
  timeout: 60000                  // 請求超時時間
})

// request攔截器
service.interceptors.request.use(config => {
  // Do something before request is sent
  Indicator.open('加載中...')
  return config
}, error => {
  // Do something with request error
  Promise.reject(error)
})

// respone攔截器
service.interceptors.response.use(
  response => {
    Indicator.close()
    const res = response.data
    if (res.ReturnCode !== '000000') {
      if (res.ReturnMsg) {
        MessageBox.alert(res.ReturnMsg)
      } else {
        MessageBox.alert('系統未知錯誤')
      }
      return Promise.reject(res)
    } else {
      return res
    }
  },
  error => {
    Indicator.close()
    MessageBox.alert('太火爆了吧,稍安勿躁,親,再試試')
    return Promise.reject(error)
  }
)
export default service
//api/xxx.js
import request from '@/utils/request'

// 登陸
export function userLogin(data) {
  return request({
    url: 'login.do',
    method: 'post',
    data
  })
}

2)跨域問題

 經常使用的方式就是 cors 全稱爲 Cross Origin Resource Sharing(跨域資源共享)。這種方案對於前端來講和平時發請求寫法上沒有任何區別,工做量基本都在後端這裏。前端也是有解決方案的,dev環境也能夠經過webpack-dev-serverproxy來解決。【webpack的dev-server 使用了很是強大的 http-proxy-middleware 包】

a、直接使用http-proxy-middleware包

//配置js1
var proxyMiddleware = require('http-proxy-middleware');
var express = require('express');
var app = express();
Object.keys(proxyTable).forEach(function (context) {
    var options = proxyTable[context]
    if (typeof options === 'string') {
        options = {target: options}
    }
    app.use(proxyMiddleware(options.filter || context, options))
});
//配置js2
proxyTable: { "/tt": { target: "http://localhost:8090", changeOrigin: true } }

b、使用webpack-dev-server此npm包(webpack的devServer配置

//webpack.dev.config.js
devServer: {
  proxy: config.dev.proxyTable
},
//配置js
proxyTable: {
  "/portal": {
    target: "http://localhost:8080"
  }
}

3)Mock 數據

mockjs:攔截請求並代理到本地模擬數據

四、權限控制

詳見http://www.javashuo.com/article/p-hjvxfzvw-km.html

作後臺項目區別於作其它的項目,權限驗證與安全性是很是重要的,能夠說是一個後臺項目一開始就必須考慮和搭建的基礎核心功能。咱們所要作到的是:不一樣的權限對應着不一樣的路由,同時側邊欄也需根據不一樣的權限,異步生成(動態根據用戶的 role 算出其對應有權限的路由,經過 router.addRoutes 動態掛載這些路由)。

//permission.js
const whiteList = ['/login']// 不重定向白名單
router.beforeEach((to, from, next) => {
  NProgress.start() // 開啓Progress
  const token = store.state.user.token
  if (token) { // 判斷是否有token
    if (to.path === '/login') {
      next({ path: '/' })
    } else {
      store.dispatch('GenerateRoutes').then(() => { // 生成可訪問的路由表
        router.addRoutes(store.getters.addRouters) // 動態添加可訪問路由表
        next()
      })
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) { // 在免登陸白名單,直接進入
      next()
    } else {
      next('/login') // 不然所有重定向到登陸頁!
    }
  }
})

五、樣式

常見的工做流程是,全局樣式都寫在 src/styles 目錄下,每一個頁面本身對應的樣式都寫在本身的 .vue 文件之中

1)使用scoped解決樣式衝突問題(基於PostCss的,加了一個做用局的概念)

//編譯前
.example {
  color: red;
}
//編譯後
.example[_v-f3f3eg9] {
  color: red;
}

2)自定義 element-ui 樣式

因爲element-ui的樣式咱們是在全局引入的,因此你想在某個view裏面覆蓋它的樣式就不能加scoped,但你又想只覆蓋這個頁面的element樣式,你就可在它的父級加一個class,以用命名空間來解決問題。

.aritle-page{ //你的命名空間
    .el-tag { //element-ui 元素
      margin-right: 0px;
    }
}

六、ECharts

管理後臺圖表也是常見的需求。ECharts支持webpack引入,圖省事能夠將ECharts整個引入;不過ECharts仍是不小的,咱們大部分狀況只是用到不多一部分功能,所以能夠按需引入的。

// 引入 ECharts 主模塊
var echarts = require('echarts/lib/echarts');
// 引入柱狀圖
require('echarts/lib/chart/bar');
// 引入提示框和標題組件
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');

七、使用icon圖標

雪碧圖,就是將多個圖片合成一個圖片,而後利用 css background-position 定位顯示不一樣的 icon 圖標。但這個也有一個很大的痛點,維護困難。每新增一個圖標,都須要改動原始圖片,還可能不當心出錯影響到前面定位好的圖片,並且一修改雪碧圖,圖片緩存就失效了,長此以往你不知道該怎麼維護了。

Iconfont-阿里巴巴矢量圖標庫symbol引用:這是一種全新的使用方式,應該說這纔是將來的主流,也是平臺目前推薦的用法。

  • 支持多色圖標了,再也不受單色限制。
  • 經過一些技巧,支持像字體那樣,經過font-size,color來調整樣式。
  • 兼容性較差,支持 ie9+,及現代瀏覽器。
  • 瀏覽器渲染svg的性能通常,還不如png。

第一步:拷貝項目下面生成的symbol代碼:

引入  ./iconfont.js

第二步:加入通用css代碼(引入一次就行):

<style type="text/css">
    .icon {
       width: 1em; height: 1em;
       vertical-align: -0.15em;
       fill: currentColor;
       overflow: hidden;
    }
</style>

第三步:挑選相應圖標並獲取類名,應用於頁面:

<svg class="icon" aria-hidden="true"> <use xlink:href="#icon-xxx"></use> </svg>

1)建立icon-svg組件

<!--components/Icon-svg-->
<template>
  <svg class="svg-icon" aria-hidden="true">
    <use :xlink:href="iconName"></use>
  </svg>
</template>

<script>
export default {
  name: 'icon-svg',
  props: {
    iconClass: {
      type: String,
      required: true
    }
  },
  computed: {
    iconName() {
      return `#icon-${this.iconClass}`
    }
  }
}
</script>
//引入svg組件
import IconSvg from '@/components/IconSvg'
//全局註冊icon-svg
Vue.component('icon-svg', IconSvg)
//在代碼中使用
<icon-svg icon-class="password" />

2)使用 svg-sprite優化

a、優化緣由:如今全部的 svg-sprite 都是經過 iconfont 的 iconfont.js 生成的

  • 首先它是一段用js來生成svg的代碼,全部圖標 icon 都很不直觀。你徹底不知道哪一個圖標名對應什麼圖標, 每次增刪改圖標只能總體js文件一塊兒替換。
           如圖所示
  • 其次它也作不到按需加載,不能根據咱們使用了那些 svg 動態的生成 svg-sprite
  • 自定義性差,一般導出的svg包含大量的無用信息,例如編輯器源信息、註釋等。一般包含其它一些不會影響渲染結果或能夠移除的內容。
  • 添加不友善,若是我有一些自定義的svg圖標,該如何和原有的 iconfont 整合到一塊兒呢?目前只能將其也上傳到 iconfont 和原有的圖標放在一個項目庫中,以後再從新下載,很繁瑣。

b、在 vue-cli 的基礎上進行改造,加入 svg-sprite-loader(能夠將多個 svg 打包成 svg-sprite

   vue-cli默認狀況下會使用  url-loader 對svg進行處理,會將它放在 /img 目錄下,因此這時候咱們引入 svg-sprite-loader 會引起一些衝突(解決方案有兩種,最簡單的就是你能夠將 test 的 svg 去掉,這樣就不會對svg作處理了,固然這樣作是很不友善的:你不能保證你全部的 svg 都是用來當作 icon的,有些真的可能只是用來當作圖片資源的;不能確保你使用的一些第三方類庫會使用到 svg)。最安全合理的作法是使用 webpack 的 exclude 和 include ,讓 svg-sprite-loader只處理你指定文件夾下面的 svg, url-loaer只處理除此文件夾以外的全部svg。
//webpack.base.config.js
{
  test: /\.svg$/,
  loader: 'svg-sprite-loader',
  include: [resolve('src/icons')],
  options: {
    symbolId: 'icon-[name]'
  }
},
{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  loader: 'url-loader',
  exclude: [resolve('src/icons')],
  options: {
    limit: 10000,
    name: utils.assetsPath('img/[name].[hash:7].[ext]')
  }
}

c、自動導入

咱們建立一個專門放置圖標 icon 的文件夾如:@/src/icons,將全部 icon 放在這個文件夾下。以後咱們就要使用到 webpack require.contextrequire.context有三個參數(directory:說明須要檢索的目錄;useSubdirectories:是否檢索子目錄;regExp: 匹配文件的正則表達式)

//src/icons/index.js
const requireAll = requireContext => requireContext.keys().map(requireContext)
const svgs = require.context('./svgs', false, /\.svg$/)
//去
svgs文件夾(不包含子目錄)下面的找全部文件名以  結尾的文件
requireAll(svgs)
.svg

 3)進一步優化本身的svg-移除無用信息

  iconfont 網站導出的 svg 內容已經算蠻精簡的了,但你會發現其實仍是與不少無用的信息,形成了沒必要要的冗餘。好在 svg-sprite-loader也考慮到了這點,它目前只會獲取 svg path 的內容,而其它的信息一律不會獲取。但任何你在 path 中產生的冗餘信息它就不會作處理了,如註釋什麼的。這時候咱們就要使用另外一個很好用的東西了-- svgo:由於SVG文件,尤爲從各類變假期導出的SVG,一般包含大量的無用信息,例如編輯器源信息,註釋,所以默認或者非最優值以及其餘一些不會影響渲染結果的元素能夠移除或轉換。

相關文章
相關標籤/搜索