Vue-Router-Webpack 模块化开发
项目目的
不使用vue-cli脚手架,从头搭建Vue模块化开发环境
Github仓库地址:https://github.com/Zimomo333/Vue-Router-Webpack
项目功能
导航栏(折叠)
面包屑
Vue-Router(路由功能)
Wepack打包压缩,热加载本地服务器
项目依赖
- Vue
- Vue Router
- Element-UI
- webpack
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| npm init npm i vue -S
npm i element-ui -S
npm i vue-router -S
npm i webpack webpack-dev-server -D // 热加载本地server,用于运行打包后的dist资源
<!-- webpack loader --> npm i vue-loader vue-template-compiler -D // 解析vue文件、模板 npm i css-loader style-loader -D // 解析Element-UI的CSS文件 npm i file-loader -D // 解析Element-UI的字体文件
<!-- webpack plugin --> npm i html-webpack-plugin -D // 自动生成注入js的index.html
|
目录结构
结构说明:
文件/目录名 |
作用 |
webpack.config.js |
webpack 配置文件 |
routes.js |
Vue Router 配置文件 |
main.js |
全局配置,webpack 打包入口 |
App.vue |
Vue 根组件 |
public/index.html |
HtmlWebpackPlugin 自定义index.html 模板 |
views 目录 |
页面组件(业务页面) |
components 目录 |
公用组件(导航栏、面包屑) |
dist 目录 |
webpack 打包输出目录 |
node_modules 目录 |
npm 模块下载目录 |
Vue-Router
router.js
以 /
开头的嵌套路径会被当作根路径,因此子路由的path无需加 /
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import Vue from 'vue' import VueRouter from 'vue-router'
Vue.use(VueRouter)
export const routes = [ { path: '/info', component: () => import('./views/info.vue'), meta: { title: '个人中心', icon: 'el-icon-user-solid' } }, { path: '/orders', component: () => import('./views/orders/index.vue'), meta: { title: '订单管理', icon: 'el-icon-s-order' }, children: [ { path: 'my-orders', component: () => import('./views/orders/myOrders.vue'), meta: { title: '我的订单', icon: 'el-icon-s-order' } }, { path: 'submit', component: () => import('./views/orders/submit.vue'), meta: { title: '提交订单', icon: 'el-icon-s-order' } } ] } ]
const router = new VueRouter({ routes })
export default router
|
Webpack
webpack.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| const path = require('path') const VueLoaderPlugin = require('vue-loader/lib/plugin') const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { entry: './src/main.js', output: { path: path.resolve(__dirname, './dist'), filename: 'bundle.js' }, devServer: { contentBase: './dist' }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader' }, { test: /\.css$/, loader: "style-loader!css-loader" }, { test: /\.(woff|ttf)$/, loader: 'file-loader' } ] }, plugins: [ new VueLoaderPlugin(), new HtmlWebpackPlugin({ title: 'Vue-wepack demo', template: './public/index.html' }) ] }
|
public/index.html
模板
默认生成的index.html
没有 id=”app” 挂载点,必须使用自定义模板
1 2 3 4 5 6 7 8 9 10 11
| <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> </div> </body> </html>
|
组件
App.vue
import { xxx } from './xxx'
指定需要引用的模块
<style scoped>
scoped 范围css 防止全局污染
增加了一个全局样式,解决导航栏折叠时子菜单文字不隐藏的bug
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| <template> <div id="app"> <el-row class="tac"> <el-col :span="4"> <el-radio-group v-model="isCollapse"> <el-radio-button :label="false">展开</el-radio-button> <el-radio-button :label="true">收起</el-radio-button> </el-radio-group> <h3>导航栏</h3> <el-menu :default-active="this.$route.path" :collapse="isCollapse" router > <sidebar-item v-for="route in routes" :key="route.path" :item="route" /> </el-menu> </el-col> <el-col :span="16"> <el-breadcrumb separator="/"> <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item> <el-breadcrumb-item v-for="item in this.$route.matched" :key="item.path" :to="item.path" > {{item.meta.title}} </el-breadcrumb-item> </el-breadcrumb> <h3>正文</h3> <router-view /> </el-col> </el-row> </div> </template>
<script> import { routes } from './router' // {}指定需要引用的模块 import SidebarItem from './components/SidebarItem.vue'
export default { name: 'App', components: { SidebarItem }, data() { return { isCollapse: true, routes } } } </script>
<style scoped> /* scoped 范围css 防止全局污染 */ h3 { text-align: center; } .el-breadcrumb { font-size: 1.17em; margin: 21.92px; } .el-radio-group { width:100%; display: flex; justify-content: center; margin-top: 13px; } </style>
<style> /* 解决导航栏折叠子菜单文字不隐藏的bug,必须覆盖全局样式 */ /* 隐藏文字 */ .el-menu--collapse .el-submenu__title span{ display: none; } /* 隐藏 > , 默认该i元素标签无hash值,因此scoped无效,必须使用全局样式覆盖 */ .el-menu--collapse .el-submenu__title .el-submenu__icon-arrow{ display: none; } </style>
|
组件自调用实现嵌套导航栏
传递basePath记录父路由路径,与子路由拼接成完整路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <template> <!-- 隐藏不需要显示的路由 --> <div v-if="!item.hidden"> <!-- 如果没有子路由 --> <template v-if="!item.children"> <el-menu-item :key="item.path" :index="resolvePath(item.path)"> <i :class="item.meta.icon"></i> <span slot="title">{{item.meta.title}}</span> </el-menu-item> </template> <!-- 如果有子路由,渲染子菜单 --> <el-submenu v-else :index="resolvePath(item.path)"> <template slot="title"> <i :class="item.meta.icon"></i> <span slot="title">{{item.meta.title}}</span> </template> <sidebar-item v-for="child in item.children" :key="child.path" :item="child" :basePath="resolvePath(item.path)" /> </el-submenu> </div> </template>
<script> import path from 'path'
export default { name: 'SidebarItem', //组件自调用,必须有name属性 props: { //接收父组件传参 item: { type: Object, required: true }, basePath: { //从父组件一直拼接下来的基路径 type: String, default: '' } }, methods: { //拼接父子路径 resolvePath(routePath) { return path.resolve(this.basePath,routePath) } } } </script>
|
项目展示