[关闭]
@Bios 2019-10-09T09:50:49.000000Z 字数 12293 阅读 1715

Vue2.0 + ElementUi后台管理系统知识点整理

Vue ElementUi


vuejs tab选项卡

  1. <template>
  2. <ul class="tab clearfix">
  3. <li v-for="(tab,index) in tabs" @click="changeTab(index,tab.view)" :class="{active:currentActive===index}">
  4. {{tab.type}}
  5. </li>
  6. </ul>
  7. </template>
  8. <script>
  9. import GroupFile from 'components/group/GroupFile'
  10. import GroupSetting from 'components/group/GroupSetting'
  11. import MembersList from 'components/group/MembersList'
  12. export default {
  13. // view 为组件名
  14. data() {
  15. return {
  16. tabs:[
  17. {type:'互动交流',view:'GroupChat'},
  18. {type:'文件共享',view:'GroupFile'},
  19. {type:'小组设置',view:'GroupSetting'}
  20. ]
  21. }
  22. },
  23. methods:{
  24. // tab切换 添加active类
  25. changeTab(index,view) {
  26. this.currentActive = index
  27. this.currentView = view
  28. }
  29. },
  30. components: {
  31. GroupChat,
  32. GroupFile,
  33. GroupSetting
  34. }
  35. }
  36. </script>

Element 根据table数据的选中项,设置按钮的disabled

  1. <template>
  2. <el-table
  3. ref="multipleTable"
  4. :data="tableData"
  5. border
  6. tooltip-effect="dark"
  7. style="width: 100%"
  8. @selection-change="handleSelectionChange"
  9. >
  10. <el-table-column
  11. type="selection"
  12. width="55">
  13. </el-table-column>
  14. <el-table-column
  15. prop="filename"
  16. label="文件名"
  17. width="500">
  18. </el-table-column>
  19. ……
  20. </el-table>
  21. </template>
  22. <script>
  23. export default{
  24. data() {
  25. return {
  26. multipleSelection: [] //存放选择项
  27. }
  28. },
  29. computed:{
  30. isSelected() {
  31. if (this.multipleSelection.length > 0) {
  32. return false
  33. } else {
  34. return true
  35. }
  36. }
  37. },
  38. methods:{
  39. handleSelectionChange(val) {
  40. // val是个为当前选中行
  41. this.multipleSelection = val
  42. }
  43. }
  44. }
  45. </script>

Element 删除选中的数据

  1. ……结构与上面一样 在删除按钮上绑定delet()方法
  2. delet() {
  3. //console.log(this.multipleSelection)
  4. this.tableData.splice(this.multipleSelection,this.multipleSelection.length)
  5. this.$refs.multipleTable.clearSelection(); // 清空用户的选择,否则它会自动向上选中this.multipleSelection.length个数据
  6. }

Element 表格中每一行添加独立的radio

  1. <template>
  2. <el-table
  3. :data="listTableData"
  4. border
  5. style="width: 100%">
  6. <el-table-column
  7. prop="name"
  8. label="名称"
  9. >
  10. </el-table-column>
  11. <el-table-column
  12. label="是否使用"
  13. width="150">
  14. <template scope="scope">
  15. <el-radio class="radio" v-model="scope.row.useradio" label="1"></el-radio>
  16. <el-radio class="radio" v-model="scope.row.useradio" label="2"></el-radio>
  17. </template>
  18. </el-table-column>
  19. <el-table-column
  20. label="是否必填"
  21. width="150">
  22. <template scope="scope">
  23. <el-radio class="radio" v-model="scope.row.needradio" label="1"></el-radio>
  24. <el-radio class="radio" v-model="scope.row.needradio" label="2"></el-radio>
  25. </template>
  26. </el-table-column>
  27. </el-table>
  28. </template>
  29. <script>
  30. export default{
  31. data() {
  32. return {
  33. listTableData:[
  34. {
  35. name:'主要学习经历',
  36. useradio:'1',
  37. needradio:'1'
  38. },
  39. {
  40. name:'主要工作经历',
  41. useradio:'1',
  42. needradio:'1'
  43. }
  44. ]
  45. }
  46. }
  47. }
  48. </script>

vue跳转页面携带参数,在目标页面判断,以实现按需展示

跳转传参

  1. <router-link :to="{name:'预选编委',query:{bookid:scope.row.bookid,edit:1}}">

路由判断

  1. data() {
  2. return {
  3. edit:''
  4. }
  5. }
  6. created(){
  7. if(this.$route.query.edit===1) {
  8. this.edit=true
  9. }else {
  10. this.edit=false
  11. }
  12. }

是否展示

  1. <el-table-column
  2. v-if="!edit"
  3. label="是否编委"
  4. align="center"
  5. >
  6. <template scope="scope">
  7. <el-tag :type="scope.row.isMember==='编委'?'success':'danger'">{{ scope.row.isMember}}</el-tag>
  8. </template>
  9. </el-table-column>

router.go(n)

这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)

例子

  1. // 在浏览器记录中前进一步,等同于 history.forward()
  2. router.go(1)
  3. // 后退一步记录,等同于 history.back()
  4. router.go(-1)
  5. // 前进 3 步记录
  6. router.go(3)
  7. // 如果 history 记录不够用,那就默默地失败呗
  8. router.go(-100)
  9. router.go(100)

点击表格数据,弹出层修改数据,该怎么将表格数据赋值给弹出层

  1. // 弹出层 字段跟表格一样
  2. form: {
  3. username:'',
  4. name: '',
  5. phone:'',
  6. email:'',
  7. role:'',
  8. use:''
  9. },
  10. // 表格数据
  11. tableData:[
  12. {
  13. name:'张三',
  14. username:'zs',
  15. email:'123@qq.com',
  16. role:'主任项目编辑',
  17. phone:'1383838438',
  18. use:false
  19. },
  20. ……
  21. ]
  1. // 点击修改
  2. modify(index, data) {
  3. //this.form = data[index] 要通过遍历的方式赋值,而不能直接将对象赋值,这样数据会及时修改(内存地址赋值了)
  4. for (var key in data[index]){
  5. this.form[key] = data[index][key]
  6. // use要在页面中呈现"启用""停用",在赋值的时候做处理
  7. if (this.form.use){
  8. this.form.use = "启用"
  9. } else {
  10. this.form.use = "停用"
  11. }
  12. }
  13. },

当一个计算属性在方法中被改变时报错

  1. <template>
  2. <div class="topic_exam">
  3. <el-tabs v-model="activeName" type="border-card" >
  4. <el-tab-pane label="转发部门" name="first" v-if="Identity.isAdmin || Identity.isOpts">
  5. <forward-depart :activeName.sync='activeName' @changeActive='changeActive'></forward-depart>
  6. </el-tab-pane>
  7. <el-tab-pane label="分配编辑" name="second" v-if="Identity.isAdmin || Identity.isDirector">
  8. <distribute-editor :activeName.sync='activeName' @changeActive='changeActive'></distribute-editor>
  9. </el-tab-pane>
  10. <el-tab-pane label="受理" name="third" v-if="Identity.isAdmin || Identity.isEditor">
  11. <acceptance :activeName.sync='activeName' @changeActive='changeActive'></acceptance>
  12. </el-tab-pane>
  13. </el-tabs>
  14. </div>
  15. </template>
  16. <script type="text/javascript">
  17. import forwardDepart from './forwardDepart.vue'
  18. import distributeEditor from './distributeEditor.vue'
  19. import acceptance from './acceptance.vue'
  20. export default{
  21. data(){
  22. return{
  23. Identity:{}
  24. }
  25. },
  26. computed:{
  27. activeName:{ // 设置一个set方法可以避免错误
  28. get: function () {
  29. if (this.Identity.isAdmin || this.Identity.isOpts) {
  30. return 'first';
  31. } else if (this.Identity.isAdmin || this.Identity.isDirector) {
  32. return 'second';
  33. } else if (this.Identity.isAdmin || this.Identity.isEditor) {
  34. return 'third';
  35. }
  36. },
  37. set: function () {
  38. }
  39. }
  40. },
  41. created(){
  42. this.activeName = this.$route.query.active || 'first';
  43. this.identity();
  44. },
  45. components: {
  46. forwardDepart,distributeEditor,acceptance
  47. },
  48. methods:{
  49. changeActive(val){
  50. this.activeName=val;
  51. },
  52. identity(){
  53. this.$axios.get('/pmpheep/topic/identity').then(response=> {
  54. let res = response.data;
  55. if (res.code == '1') {
  56. this.Identity = res.data;
  57. }
  58. })
  59. }
  60. }
  61. }
  62. </script>
  63. <style scoped>
  64. .topic_exam .el-tabs--border-card{
  65. border: 0;
  66. box-shadow: none;
  67. }
  68. </style>

Vue与checkbox

  1. // 单个checkbox
  2. <input type="checkbox" v-model="a"> {{a}} <br/>
  3. // 多个checkbox
  4. 爱好:<input type="checkbox" v-model="b" value="游泳"> 游泳
  5. <input type="checkbox" v-model="b" value="爬山"> 爬山
  6. <input type="checkbox" v-model="b" value="睡觉"> 睡觉
  1. data:{
  2. return {
  3. a : false,
  4. b:['游泳','爬山'] // b可以取到checkbox的value值
  5. }
  6. }

ElementUi动态增加表单的表单验证 大坑

  1. <div v-if="dialogForm.type!='judgement'&&dialogForm.type!='Q&A'">
  2. <el-form-item v-for="(item,index) in dialogForm.surveyQuestionOptionList"
  3. :key="item.key"
  4. :label="'选项'+(index+1) +':'"
  5. :prop="'surveyQuestionOptionList.' + index + '.optionContent'"
  6. :rules="{
  7. required:true, message:'选项不能为空', trigger:'blur'
  8. }"
  9. >
  10. // 最重要的是prop 一定要带上`.optionContent`,也就是你绑定值的key
  11. <el-input placeholder="请输入选项" class="dialog_input" v-model="item.optionContent"></el-input>
  12. <i class="el-icon-delete delete-icon" @click="deleteDlalogOption(index)"></i>
  13. </el-form-item>
  14. <el-button type="primary" size="small" class="marginB10" @click="addDialogOption">添加选项</el-button>
  15. </div>

query要用path来引入,params要用name来引入

  1. goToExam(id){
  2. // params传参只能用name引入
  3. this.$router.push({name:'ForntExam',params:{id:id}});
  4. }

Elementui 单选框对上单选题

  1. <div class="single">
  2. <h4>单选题(只有一个正确答案)</h4>
  3. <ul>
  4. <li class="marginB10" v-for="(item,index) in singleQuestions" :key="item.id">
  5. <p class="question-title">{{index+1}} 、{{item.name}}()</p>
  6. <span class="option"
  7. v-if="item.type!='judgement'&&item.type!='Q&A'"item
  8. v-for="(item1,index1) in item.selection" :key="item1.id">
  9. <el-radio v-model="item.sanswer" :label="options[index1]" :key="index1">{{options[index1]}}、{{item1}}</el-radio>
  10. </span>
  11. </li>
  12. </ul>
  13. </div>
  1. init(){
  2. if(this.id == '' || !this.id ){
  3. this.$router.push({path:'forntexamindex'});
  4. return
  5. } else {
  6. this.$axios.get('/api/getExamInfo',{
  7. params:{
  8. id: this.id
  9. }
  10. }).then(response => {
  11. let res = response.data;
  12. if(res.status == '0') {
  13. for(let key in this.paperData) {
  14. this.paperData[key] = res.result[key];
  15. }
  16. res.result._questions.forEach(item => {
  17. if(item.type=='single'){
  18. item.sanswer = ''; // 重要的在这
  19. this.singleQuestions.push(item);
  20. } else if(item.type == 'multi'){
  21. this.multiQuestions.push(item);
  22. } else if(item.type == 'Q&A') {
  23. this.QAQuestions.push(item);
  24. } else if(item.type == 'judgement'){
  25. this.judgeQuestions.push(item);
  26. }
  27. })
  28. }
  29. }).catch(err => {
  30. this.$message.error(err);
  31. })
  32. }
  33. }

axios中拿不到this

  1. this.$axios.get('https://www.easy-mock.com/mock/5b616f2e0f34b755cbc58bb4/demo').then(function(res){
  2. console.log(this);
  3. })

闭包问题,要使用箭头函数

注册自定义指令

  1. // 全局注册自定义指令
  2. Vue.directive('focus', {
  3. // 当被绑定的元素插入到 DOM 中时……
  4. inserted: function (el) {
  5. // 聚焦元素
  6. console.log(el)
  7. el.focus()
  8. }
  9. })

全局注册(directive),局部注册(directives)

动画效果

  1. .fade-enter,.fade-leave-to{
  2. opacity: 0;
  3. }
  4. .fade-enter-active,.fade-leave-active{
  5. transition: opacity 3s;
  6. }
  7. <transition name="fade">
  8. <div v-show="show">显示/隐藏</div>
  9. </transition>
  1. # 可以通过 appear 特性设置节点在初始渲染的过渡
  2. <transition
  3. name="fade"
  4. appear
  5. enter-active-class="animated fadeIn"
  6. leave-active-class="animated slideInLeft"
  7. appear-class="animated fadeIn"
  8. >
  9. <div v-show="show">显示/隐藏</div>
  10. </transition>

sessionStorage 结合 mixins 作暂存

有时候有些数据是后端配置的,obu hu不会时常更新,但是又保不齐那天会更新,用localStorage + vuex 存取的方式已经不适用了,当然可以只用vuex,在这里尝试一下mixins 和 sessionStorage 的方式。用vuex 的话,如果getter拿不到数据,我们还得手动触发一下action去发送请求,我觉得比较麻烦,写成mixins的话,整个逻辑就写一遍,其他地方都可以用了。

  1. import {
  2. getGovAgen
  3. } from '@/api/policy_api';
  4. export default {
  5. data() {
  6. return {
  7. gov_agen_options: []
  8. };
  9. },
  10. mounted() {
  11. this.getGovAgen();
  12. },
  13. methods: {
  14. // 获取发文体系
  15. getGovAgen() {
  16. let options = JSON.parse(sessionStorage.getItem('gov_agen'));
  17. if (options) {
  18. this.gov_agen_options = options;
  19. } else {
  20. getGovAgen().then(res => {
  21. if (res.code == 200) {
  22. this.gov_agen_options = res.data;
  23. sessionStorage.setItem('gov_agen', JSON.stringify(res.data));
  24. }
  25. });
  26. }
  27. }
  28. }
  29. };

provide&inject 刷新当前路由

后台管理系统,刷新当前路由,而不是刷新整个页面。provide不仅可以注入变量,还可以是方法。

  1. // layout.vue
  2. <template>
  3. <header/>
  4. <siderbar/>
  5. <div>
  6. <router-view v-if="isRouterAlive"/>
  7. </div>
  8. <footer/>
  9. </template>
  10. <script>
  11. export default {
  12. provide() {
  13. return {
  14. reload: this.reload
  15. };
  16. },
  17. data() {
  18. return {
  19. isRouterAlive: true
  20. };
  21. },
  22. methods: {
  23. // 刷新页面
  24. reload() {
  25. this.isRouterAlive = false;
  26. this.$nextTick(() => {
  27. this.isRouterAlive = true;
  28. });
  29. }
  30. }
  31. };
  32. </script>
  1. // child.vue
  2. export default{
  3. inject: ['reload'],
  4. methods: {
  5. reload() {
  6. this.reload();
  7. }
  8. }
  9. }

提示:provideinject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

elementui select 内容过长

  1. /deep/ .el-tag.el-tag--info.el-tag--small.el-tag--light {
  2. display: flex;
  3. align-items: center;
  4. }
  5. /deep/ .el-select__tags-text {
  6. max-width: 200px;
  7. display: inline-block;
  8. height: 22px;
  9. overflow: hidden;
  10. text-overflow: ellipsis;
  11. }

vue-router 打开新页面

  1. let routeUrl = this.$router.resolve({
  2. path: path,
  3. query: {type: type}
  4. });
  5. window.open(routeUrl.href, '_blank');

vue-router 的 hash 模式和 history 模式

我们先来看一个完整的 URL:https://www.baidu.com/blog/guide/vuePlugin.html#vue-router。其中 https://www.baidu.com 是网站根目录,/blog/guide/是子目录,vuePlugin.html是子目录下的文件(如果只有目录,没有指定文件,会默认请求index.html文件),而#vue-router就是哈希值。
vue 是单页应用,打包之后只有一个 index.html,将他部署到服务器上之后,访问对应文件的目录就是访问这个文件。

hash 模式的 #号很丑,使用的是 onhashchange 事件切换路由,兼容性会好一点,不需要服务器配合
history 模式好看点,但是本地开发、网站上线,都需要服务器额外配置,并且还需要自己写 404 页面,使用的是 HTML5 的 history API,兼容性差一点。

两者的配置区别在于:

  1. const router = new VueRouter({
  2. mode: 'history', //"hash"模式是默认的,无需配置
  3. base: '/',//默认配置
  4. routes: [...]
  5. })
  6. 复制代码vue-cli3 vue.config.js 配置:
  7. module.exports = {
  8. publicPath: "./", // hash模式打包用
  9. // publicPath: "/", // history模式打包用
  10. devServer: {
  11. open: true,
  12. port: 88,
  13. // historyApiFallback: true, //history模式本地开发用
  14. }
  15. }

复制代码如果是网站部署在根目录,routerbase 就不用填。如果整个单页应用服务在 /app/ 下,然后 base 就应该设为 "/app/",同时打包配置(vue.config.js)publicPath 也应该设置成/app/

vue-cli3生成新项目的时候会有选择路由的模式,选择history模式就会帮你都配置好。

路由拦截以及回跳

  1. ...
  2. routes: [
  3. {
  4. path: '/',
  5. name: 'home',
  6. component: Home,
  7. meta: {auth: true}
  8. },
  9. ]
  10. ...
  11. router.beforeEach((to, from, next) => {
  12. if(to.meta.auth) {
  13. const token = localStorage.getItem('token');
  14. if(token){
  15. next()
  16. } else {
  17. // 没有登录跳到登录页,登录之后,直接跳转到to.path
  18. next({
  19. path: '/login',
  20. query: {redirect: to.path}
  21. })
  22. }
  23. } else {
  24. next()
  25. }
  26. })

vue mock数据的两种方式

devser mock

这种方式不存在跨域。

  1. // vue.config.js
  2. module.exports = {
  3. configureWebpack: {
  4. devServer: {
  5. before(app) {
  6. app.get('/api/goods', (req, res) => {
  7. res.json({
  8. code: 0,
  9. list: [
  10. {id:1,name:'苹果'},
  11. {id:2,name:'香蕉'}
  12. ]
  13. })
  14. })
  15. }
  16. }
  17. }
  18. }
  1. axios.get('/api/goods').then(res => {})

json mock

  1. // public/mock/member.json
  2. [
  3. {"id":0,"name":"finget","age":23},
  4. {"id":1,"name":"finget1","age":23},
  5. {"id":2,"name":"finget2","age":23},
  6. {"id":3,"name":"finget3","age":23}
  7. ]
  1. // vue.config.js
  2. module.exports = {
  3. configureWebpack: {
  4. devServer: {
  5. proxy: {
  6. '/api': {
  7. target: 'http://localhost:8080',
  8. changeOrigin: true,
  9. pathRewrite: {
  10. '^/api': '/mock'
  11. }
  12. }
  13. }
  14. }
  15. }
  16. }
  1. axios.get('/api/member.json').then(res => {})

mockjs

  1. //引入mockjs
  2. const Mock = require('mockjs')
  3. // 获取 mock.Random 对象
  4. const Random = Mock.Random;
  5. //使用mockjs模拟数据
  6. Mock.mock('/api/data', (req, res) => {//当post或get请求到/api/data路由时Mock会拦截请求并返回上面的数据
  7. let list = [];
  8. for(let i = 0; i < 30; i++) {
  9. let listObject = {
  10. title: Random.csentence(5, 10),//随机生成一段中文文本。
  11. company: Random.csentence(5, 10),
  12. attention_degree: Random.integer(100, 9999),//返回一个随机的整数。
  13. photo: Random.image('114x83', '#00405d', '#FFF', 'Mock.js')
  14. }
  15. list.push(listObject);
  16. }
  17. return {
  18. data: list
  19. }
  20. })

自定义表单验证(一项中含有多个值input)

  1. <el-form-item
  2. label="地址"
  3. class="flex-1 is-required"
  4. prop="address"
  5. :rules="[
  6. {validator: addressValidator, trigger: 'blur'}
  7. ]"
  8. ></el-form-item>
  9. methods: {
  10. // 详细地址validator
  11. addressValidator(rule, value, callback) {
  12. if (this.form.address === '' || this.form.region.length === 0) {
  13. callback(new Error('请选择省市区并填写详细地址'));
  14. } else {
  15. callback();
  16. }
  17. }
  18. }

自定义表单验证(动态验证)

1.动态新增

  1. <el-form-item
  2. :label="'租金'+(index+1)"
  3. class="flex-1"
  4. :prop="'payment.rent_period.'+index+'.rent_fee'"
  5. :rules ="{
  6. pattern: /^[1-9]{1,9}$/, message: '只能输入正整数,且不超过10位数', trigger:'change'
  7. }"
  8. >

2.关联验证

  1. <el-form-item
  2. class="flex-1"
  3. label="租金时间段"
  4. :prop="'payment.rent_period.'+index+'.start_time'"
  5. :rules="item.rent_fee?{required: true, message:'请填写租金时间段', trigger: 'change'}:{}"
  6. >
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注