Vue 2.0 + Vue Router + Vuex

用 Vue.js 2.x 与相配套的 Vue Router、Vuex 搭建了一个最基本的后台管理系统的骨架。

当然先要安装 node.js(包括了 npm)、vue-cli

项目结构如图所示:

assets 中是静态资源,components 中是组件(以 .vue 为后缀名的文件),store 中是使用了 vuex 的 js 文件。

package.json:

{
  "name": "element-starter",
  "description": "A Vue.js project",
  "author": "caihg",
  "private": false,
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --inline --hot --open",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
  },
  "dependencies": {
    "element-ui": "^1.0.0",
    "vue": "^2.1.0",
    "vue-router": "^2.1.1",
    "vue-server-renderer": "^2.1.3",
    "vuex": "^2.0.0",
    "vuex-router-sync": "^3.0.0"
  },
  "devDependencies": {
    "babel-core": "^6.0.0",
    "babel-loader": "^6.0.0",
    "babel-preset-es2015": "^6.13.2",
    "cross-env": "^1.0.6",
    "css-loader": "^0.23.1",
    "file-loader": "^0.8.5",
    "style-loader": "^0.13.1",
    "vue-loader": "^10.0.0",
    "vue-template-compiler": "^2.1.0",
    "webpack": "^2.1.0-beta.25",
    "webpack-dev-server": "^2.1.0-beta.0",
    "webpack-dev-middleware": "^1.6.1"
  }
}

webpack.config.js:

var path = require('path')
var webpack = require('webpack')

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'build.js'
  },
  module: {
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        loader: 'style-loader!css-loader'
      },
      {
        test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
        loader: 'file-loader'
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?\S*)?$/,
        loader: 'file-loader',
        query: {
          name: '[name].[ext]?[hash]'
        }
      }
    ]
  },
  devServer: {
    historyApiFallback: true,
    noInfo: true
  },
  devtool: '#eval-source-map'
}

if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ])
}

项目的入口 js 文件 main.js:

import Vue from 'vue'
import VueRouter from 'vue-router'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-default/index.css'

Vue.use(VueRouter)
Vue.use(ElementUI)

import routes from './routes'
const router = new VueRouter({
  mode: 'history',
  base: __dirname,
  routes: routes
})

import Main from './components/main.vue'
new Vue({
  el: '#app',
  router,
  render: h => h(Main)
})

该文件引用了路由配置文件 routes.js 和主入口的组件 main.vue,其中 main.vue 在 components 目录

 

routes.js 内容如下:

import Login from './components/login/login.vue'
import Container from './components/container/container.vue'
import UserHome from './components/container/userHome.vue'
import Platform from './components/asideContainer/platform.vue'
import UserList from './components/platform/userList.vue'
import UserCreate from './components/platform/userCreate.vue'
import Product from './components/asideContainer/product.vue'
import ProductList from './components/product/list.vue'
import ProductBrand from './components/product/brand.vue'
import NotFound from './components/error/notFound.vue'

export default [
  {
    path: '/login',
    component: Login
  },
  {
    path: '/',
    redirect: '/login'
  },
  {
    path: '/page',
    component: Container,
    children: [
      {
        path: 'userHome',
        component: UserHome
      },
      {
        path: 'platform',
        redirect: 'platform/userList', // 默认指向用户列表(UserList)
        component: Platform,
        children: [
          {
            path: 'userList',
            component: UserList
          },
          {
            path: 'userCreate',
            component: UserCreate
          }
        ]
      },
      {
        path: 'product',
        redirect: 'product/list', // 默认指向商品列表(ProductList)
        component: Product,
        children: [
          {
            path: 'list',
            component: ProductList
          },
          {
            path: 'brand',
            component: ProductBrand
          }
        ]
      }
    ]
  },
  { // 404页面:必须位于最后,否则其它的路由地址都会使用 NotFound 组件
    path: '*',
    component: NotFound
  }
]

main.vue 的内容如下:

<template>
  <router-view></router-view>
</template>

 store.js 在 store 目录,内容如下:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    username: ''
  }
})

 

后台都是登录成功后跳转到主页面

 

界面的 UI 用的是开源的 element-ui

login.vue 位于 login 目录,内容如下:

<template>
  <div class="box">
    <el-form :model="loginForm" :rules="loginRules" ref="loginForm" label-width="100px" class="form-box">
      <el-form-item label="用户名" prop="username">
        <el-input v-model="loginForm.username" placeholder="请输入用户名" auto-complete="off"></el-input>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input type="password" v-model="loginForm.password" auto-complete="off"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onLogin">登录</el-button>
        <el-button @click="handleReset">重置</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import store from '../../store/store'
export default {
  data() {
    var validateUsername = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入用户名'));
      } else {
        callback();
      }
    };
    var validatePassword = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入密码'));
      } else {
        callback();
      }
    };

    return {
      loginForm: {
        username: '',
        password: ''
      },
      loginRules: {
        username: [
          { validator: validateUsername, trigger: 'blur' }
        ],
        password: [
          { validator: validatePassword, trigger: 'blur' }
        ]
      }
    };
  },
  methods: {
    onLogin(event) {
      this.$refs.loginForm.validate((valid) => {
        if (valid) {
          store.state.username = this.loginForm.username;
          this.$router.push('page/userHome');
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
    handleReset() {
      this.$refs.loginForm.resetFields();
    }
  }
}
</script>

<style>
.form-box {
  width: 500px;
  margin-top: 100px;
  margin-right: auto;
  margin-left: auto;
}
</style>

在登录事件中,将用户名传递给 store 中的 state.username,以便在其它组件中获取: 

store.state.username = this.loginForm.username

 

登录后的界面,默认跳转到主页:

 

通过 vuex 获取到了登录的用户名称(caihg);当然,如果刷新当前页面,用户名称就没了。 

头部在 container 目录,其中有三个组件

container.vue 的内容如下:

<template>
  <div class="container">
    <header-nav></header-nav>
    <router-view></router-view>
  </div>
</template>

<script>
import headerNav from './headerNav.vue'
export default {
  components: {
    headerNav
  }
}
</script>

<style>
header > h1 {
  display: inline-block;
}
header > a {
  margin: 0 10px;
  color: #000;
  text-decoration: none;
}
</style>

headerNav.vue 中就是头部导航的各种链接:

<template>
  <header>
    <h1>管理平台</h1>
    <router-link to="/page/userHome">主页</router-link>
    <router-link to="/page/platform">平台管理</router-link>
    <router-link to="/page/product">商品管理</router-link>
    <strong>欢迎你,{{ getUsername }}</strong>
  </header>
</template>

<script>
import store from '../../store/store'
export default {
  computed: {
    getUsername () {
      return store.state.username
    }
  }
}
</script>

<style>
header > .router-link-active {
  color: red;
}
header > strong {
  padding-left: 50px;
}
</style>

 

点击头部的导航,下面的内容相应地切换

 其中左侧部分也是导航,点击也要跟随切换

左侧的导航放在 asideContainer 目录

 platform.vue 与 product.vue 内容相似;只是前者包括了样式,后者没有(相同的样式写一份就够了,如果多写了,也会重复渲染)

<template>
  <!-- 平台管理 -->
  <div>
    <ul class="aside-nav">
      <li><router-link to="/page/platform/userList">用户列表</router-link></li>
      <li><router-link to="/page/platform/userCreate">用户创建</router-link></li>
    </ul>
    <router-view class="aside-container"></router-view>
  </div>
</template>

<style>
.aside-nav {
  float: left;
  width: 100px;
  margin: 0 50px 0 0;
  padding-left: 0;
}
.aside-nav a {
  display: block;
  padding: 4px 0 5px;
  color: #555;
  text-align: center;
  text-decoration: none;
}
.aside-nav .router-link-active {
  color: #fff;
  background-color: orange;
}
.aside-container {
  float: left;
}
</style>
<template>
  <!-- 商品管理 -->
  <div>
    <ul class="aside-nav">
      <li><router-link to="/page/product/list">商品列表</router-link></li>
      <li><router-link to="/page/product/brand">商品品牌</router-link></li>
    </ul>
    <router-view class="aside-container"></router-view>
  </div>
</template>

 

左侧导航对应的内容分别在不同的目录(根据功能划分)

userList.vue 中的内容如下:

<template>
  <div>
    用户列表的内容
  </div>
</template>

至此完成,后台管理系统的大致骨架就是这样了。

项目代码在 github 上

posted on 2016-12-09 16:38  caihg  阅读(2215)  评论(0编辑  收藏  举报