https://github.com/helloyoucan/ba
用 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 上