npm install
npm run serve
npm run build
npm run lint
git checkout -b name
:创建一个名为name的分支template
(一: 模板) script
(二: 属性/方法) <style lang="less" scoped>
(三: 样式 支持less并且具有作用域)redirect
如果用户访问的是根路由路径 会自动重定向到登录的路由组件position: abolut
和 transform: translate(-50%, -50%);
样式居中plugins
文件夹下的element.js
配置引入的 {Button, Form, FormItem, Input}
<el-form label-width="80px">
(表单默认label属性占位80px) <el-form-item label="用户名">
(一个项使用label属性左侧文字的显示)
<el-form :rules="form" :model="loginForm">
form的对象中 loginForm
的数据保存在data中<el-input v-model="loginForm.username"></el-input>
<el-form>
绑定rules
属性校验(存放在data
) 例子: rules: { name: [{ required: true, message: '请输入活动名称', trigger: 'blur' }] }
required
必填不能为空 message
错误消息提示 trigger
触发事件 min/max
最小/大输入长度prop
属性rules
调用验证: 给 el-form-item
添加而不是里面的标签 el-input
: <el-form-item prop="username">
<el-form ref='loginForm'>
绑定一个ref 通过$refs拿到组件对象,通过点击事件使用表单上自带的resetFields()重置方法表单的预登录: validate
方法 对象rules的规则进行校验也是用过$refs拿到组件调用其身上的方法
Vue.prototype.$http = axios
消息提示: 添加 message 全局(Vue原型)添加$message = Message
error:失败的提示 success:成功的提示
登录成功之后的 token,保存到客户端的 sessionStorage(会话机制/只在当前页面生效)中 / localStorage(持久话机制/关闭页面也不会忘记数据)
window.sessionStorage.setItem('token', res.data.token)
因为除了登录界面都需要token来验证操作所以登录时会保存token作为身份验证
保存token后自动跳转到后台界面 使用this.$router.push('/home')
防止别人直接访问login
以外的路由,而需要调用 路由的 导航守卫 使用 beforeEach
离开之前 检查是否有token的存在如果没有就直接跳转到 login 页面
router.beforeEach((to, from, next) => {})
to 即将跳转到哪里(到那里去) from 在哪里跳转(从哪里来) next 放行枷(给不给走)
退出登录: 在home页面设置按钮 清空token并且跳转到 login
.prettierrc
文件是JSON格式 semi
true加分号/false不加分号 singleQuote
: true为单引号/false为双引号.eslintrc.js
下取消func之间的空格: 'space-before-function-paren': 0
rules里面写git push -u remote branch
git push -u remote user
在哪个分支上就是那个分支 来推送到远程仓库element-ui 提供的组件,每个组件名都是它自己的类名
布局容器: Container Asied Main
el-menu
(最外层包裹菜单) <el-submenu>
一级菜单 <el-menu-item>
二级菜单(里层) <template>
菜单的模板(icon/span)请求拦截器: 登录授权 请求验证是否有 token 需要授权的 API ,必须在请求头中使用 Authorization
字段提供 token
令牌
Authorization
的 token令牌创建完成后立即发送 网络请求 请求左侧菜单栏的数据 get
el-menu
添加 unique-opened
属性(1) 为 true
| 折叠属性(2): collapse
| 关闭过渡动画属性(3): :collapse-transition="false"
|:width="isCollapse ? '61px' : '200px'"
利用三元表达式el-from
有router(index属性)默认为false关闭的 index='/login' index做路由跳转
:default-active="activePath"
: 点击导航-> 使用sessionStorage来保存激活的路径 并赋值给高亮的变量-> 当离开再回来created时得到 sessionStorage 的路径 赋值给 高亮变量 (导航守卫.beforeEach)el-breadcrumb
面包屑 : 首页 > 用户管理 > 用户列表el-card
配合 栅栏布局 使用 input复合框 : 样式配合 Row 和 Col的栅栏配合<el-table :data="数据源" stripe(avtice) border(边框)>
<el-table-column prop="数据名" label="列的名字">
<el-table-column>
添加template模板再使用v-slot
属性拿到当前槽作用域的布尔值 Boolean 再通过Switch组件显示 而在 <el-table-column>
使用了作用域插槽会覆盖当前层的prop所以可以删除prop 按钮使用时需要 插槽作用域pagination
: page-sizes
每页显示个数选择器的选项设置 page-size
每页显示条目个数,支持 .sync 修饰符 number layout
: 显示那些组件 监听改变事件 页码的修改 显示个数的修改 handleSizeChange(newValue)
监听显示页数的改变自带参数 是 新的值 handleCurrentChange
监听页码的改变queryInfo.query
因为搜索时根据它来的 再搜索按钮绑定点击事件发送用户数据请求,根据query返回对应的参数 , 清空搜索框并清空搜索的内容 element-ui的搜索框有自带的clear事件,点击清楚时再次发送用户数据请求,此时因为query已经清空所以返回的是默认的数据:visible.sync = DialogVisble
为true显示反之隐藏{ validator: checkEmail, trigger: 'blur' }
在验证规则里面写下validator: 变量名
就可以调用正则表达式来验证邮箱或手机号码添加两个 home 的子路由 rights/roles
权限列表: 使用卡片再用过table绑定请求来的网络数据
角色列表: 使用table 最后一项需要按钮使用作用于插槽
Dialog 对话框的关闭 表单的清空
rules
规则是否全通过返回 true 就发送相应的 修改/删除等操作el-table-column type="expand">
<template v-slot="scope">
<el-row
:class="['bdtop', i1 === 0 ? 'bdbottom' : '', 'vcenter']"
v-for="(item1, i1) in scope.row.children"
:key="item1.id"
>
<!-- 渲染一级权限 -->
<el-col :span="5">
<el-tag
closable
@close="removeRightById(scope.row, item1.id)"
>{{ item1.authName }}</el-tag
>
<i class="el-icon-caret-right"></i>
</el-col>
<!-- 渲染二和三级权限 -->
<el-col :span="19">
<!-- 通过 for 嵌套 渲染二级权限 -->
<el-row
v-for="(item2, i2) in item1.children"
:key="item2.id"
:class="[i2 === 0 ? '' : 'bdtop', 'vcenter']"
>
<el-col :span="6">
<el-tag
type="success"
closable
@close="removeRightById(scope.row, item2.id)"
>
{{ item2.authName }}
</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<el-col :span="18">
<el-tag
type="warning"
:class="[i3 === 0 ? '' : 'bdtop']"
v-for="(item3, i3) in item2.children"
:key="item3.id"
closable
@close="removeRightById(scope.row, item3.id)"
>
{{ item3.authName }}
</el-tag>
</el-col>
</el-row>
</el-col>
</el-row>
<!-- <pre>
{{ scope.row }}
</pre> -->
</template>
</el-table-column>
show-checkbox
以复选框的形式 node-key="id"
绑定id
:default-checked-keys="defKeys"
默认选中的 使用递归推送到数组中 没有子了直接推进数组 否则重再调用自己
树形表格:由于 element-ui 没有 树形的表格要借助于第三方的 vue-table-with-tree-grid
github地址
分页: 由于获取用户的方法关系,可以每次修改 页码 或 页数 时直接重新发送获取用户请求
分类的添加:
<!-- 添加分类的对话框 -->
<el-dialog
title="添加分类"
:visible.sync="addCateDialogVisible"
width="50%"
@close="addCateDialogClosed"
>
<el-form
:model="addCateForm"
:rules="addCateFormRules"
ref="addCateFormRef"
label-width="100px"
>
<el-form-item label="分类名称:" prop="cat_name">
<el-input v-model="addCateForm.cat_name"></el-input>
</el-form-item>
<el-form-item label="父级分类:">
<!-- options 用来指定数据源 -->
<!-- props 用来指定配置对象 expandTrigger: 触发方式 value(id) label(显示的文字) children(下层元素) -->
<!-- v-model 双向绑定keys -->
<el-cascader
v-model="selectdKeys"
:options="parentCateList"
:props="{
expandTrigger: 'hover',
...cascaderProps,
checkStrictly: 'true'
}"
@change="parentCateChanged"
clearable
></el-cascader>
</el-form-item>
</el-form>
<tree-table
:data="cateList"
:expand-type="false"
:selection-type="false"
show-index
class="treetable"
index-text="#"
stripe
border
:show-row-hover="false"
:columns="columns"
>
<!-- 是否有效 -->
<!-- <template slot='isok' v-slot="scope"> -->
<template v-slot:isok="scope">
<i
class="el-icon-success"
v-if="scope.row.cat_deleted === false"
style="color: lightgreen"
></i>
<i class="el-icon-error" style="color: red" v-else></i>
</template>
<!-- 排序 -->
<template v-slot:order="scope">
<el-tag size="mini" v-if="scope.row.cat_level === 0">一级</el-tag>
<el-tag
size="mini"
type="success"
v-else-if="scope.row.cat_level === 1"
>二级</el-tag
>
<el-tag size="mini" type="warning" v-else>三级</el-tag>
</template>
<template v-slot:opt="scope">
<el-button
type="primary"
@click="showeditCateDialog(scope.row)"
icon="el-icon-edit"
size="mini"
>编辑</el-button
>
<el-button
type="danger"
@click="removeCate(scope.row.cat_id)"
icon="el-icon-delete"
size="mini"
>删除</el-button
>
</template>
</tree-table>
级联选择框
<el-cascader
v-model="addForm.goods_cat" 选择出来的keys
:options="cateList" 绑定的数据元
:props="{ expandTrigger: 'hover', ...cateProps (要显示的东西) }"
@change="handleChange" 选择项发生变化
></el-cascader>
cateProps: {
label: 'cat_name', 显示的名字
value: 'cat_id', 双向绑定的id
children: 'children' 显示的子项
}
<!-- 渲染表单的item项 -->
<el-form-item
:label="item.attr_name"
v-for="item in manyTableData"
:key="item.attr_id"
>
<el-checkbox-group v-model="item.attr_vals">
<el-checkbox
border
:label="item"
v-for="(item, i) in item.attr_vals"
:key="i"
>{{ item }}</el-checkbox
>
</el-checkbox-group>
</el-form-item>
图片的上传
使用 element-ui的upload 删除操作
// 处理移除图片的操作
handleRemove(file) {
// 1. 获取将要删除的图片的临时路径
const filePath = file.response.data.tmp_path
// 2. 从 pics 数组中找到这个图片的对应的索引值
const index = this.addForm.pics.findIndex(x => x.pic === filePath)
// 3. 调用数组的splice方法,把图片信息对象,从pics数组中移除
this.addForm.pics.splice(index, 1)
console.log('移除图片', file, this.addForm)
}
富文本: vue-quill-editor
nprogress 加载时进度条
打包是 console的处理: babel-plugin-transform-remove-console
生成打包报告
项目优化 配置webpack
如果程序员有修改 webpack 默认配置的需求,可以在项目根目录中,按需创建 vue.config.js 这个配置文件,从
而对项目的打包发布过程做自定义的配置(具体配置参考 https://cli.vuejs.org/zh/config/#vue-config-js)。
在 vue.config.js 导出的配置对象中,新增 configureWebpack 或 chainWebpack 节点,来自定义 webpack
的打包配置。
在这里, configureWebpack 和 chainWebpack 的作用相同,唯一的区别就是它们修改 webpack 配置的方
式不同:
① chainWebpack 通过链式编程的形式,来修改默认的 webpack 配置
② configureWebpack 通过操作对象的形式,来修改默认的 webpack 配置
两者具体的使用差异,可参考如下网址:
通过 externals 加载外部 CDN 资源
路由来加载
// 分组名生成文件
const Login = () => import(/* webpackChunkName: "login_home_welome" */ 'components/login/Login')
const Home = () => import(/* webpackChunkName: "login_home_welome" */ 'components/home/Home')
const Welcome = () => import(/* webpackChunkName: "login_home_welome" */ 'components/home/welcome/Welcome')
const Users = () => import(/* webpackChunkName: "Users_Rights_Roles" */ 'components/home/users/Users')
const Rights = () => import(/* webpackChunkName: "Users_Rights_Roles" */ 'components/home/power/rights/Rights')
const Roles = () => import(/* webpackChunkName: "Users_Rights_Roles" */ 'components/home/power/roles/Roles')
const Cate = () => import(/* webpackChunkName: "Cate_Params" */ 'components/home/goods/cate/Cate')
const Params = () => import(/* webpackChunkName: "Cate_Params" */ 'components/home/goods/params/Params')
const GoodsList = () => import(/* webpackChunkName: "GoodsList_Add" */ 'components/home/goods/list/List')
const Add = () => import(/* webpackChunkName: "GoodsList_Add" */ 'components/home/goods/list/children/Add')
const Order = () => import(/* webpackChunkName: "Order_Report" */ 'components/home/order/Order')
const Report = () => import(/* webpackChunkName: "Order_Report" */ 'components/home/report/Report')
// 独立生成一个文件
const Login = () => import('components/login/Login')
const Home = () => import('components/home/Home')
const Welcome = () => import('components/home/welcome/Welcome')
const Users = () => import('components/home/users/Users')
const Rights = () => import('components/home/power/rights/Rights')
const Roles = () => import('components/home/power/roles/Roles')
const Cate = () => import('components/home/goods/cate/Cate')
const Params = () => import('components/home/goods/params/Params')
const GoodsList = () => import('components/home/goods/list/List')
const Add = () => import('components/home/goods/list/children/Add')
const Order = () => import('components/home/order/Order')
const Report = () => import('components/home/report/Report')
开启gzip包 compression
开启 HTTPS
pm2 关闭命令行窗口依旧执行
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。