近况

好久没写博客了,现在已经是5月14号了,在家过完年后,学完多线程到3月份,然后准备毕设项目到现在
毕设项目就把若依的后台管理项目改造了一下,加了一个前台展示模块,不知道为什么,在家好没有动力啊
太堕落了,前段时间刚答完辩,很烦,搞了这么长时间的项目,竟然草草就过了,略感有点不值得自己的准备吧
不过也没关系了,我也在学习项目的过程中,学到了一点点知识,这两天记录一下吧。

文章目录

vue使用svg组件

vue中如何使用图标呢?让我们来看看若依中怎么做的

  • 首先来到main.js,所有组件都必须直接或间接在main.js才能让webpack管理起来

    import './assets/icons'	//引入icons文件夹下的index.js文件 
  • assets/icons目录中的index.js文件

    import Vue from 'vue'
    import SvgIcon from '@/components/SvgIcon'   //图标组件 
    
    // 全局注册
    Vue.component('svg-icon', SvgIcon)
    
    //这部分代码作用是:将./svg目录下的所有svg文件全部引入webpack中,被作为模块管理起来
    //更多解释请看本节最后的文章与资源
    const req = require.context('./svg', false, /\.svg$/)
    const requireAll = requireContext => requireContext.keys().map(requireContext)
    requireAll(req)
  • 若依的SvgIcon组件,包装elementUI的图标组件

    <template>
      <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
      <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
        <use :xlink:href="iconName" />
      </svg>
    </template>
    
    <script>
    import { isExternal } from '@/utils/validate'
    
    export default {
      name: 'SvgIcon',
      props: {
        iconClass: {
          type: String,
          required: true
        },
        className: {
          type: String,
          default: '' 
        }
      },
      computed: {
        isExternal() {
          return isExternal(this.iconClass)
        },
        iconName() {
          return `#icon-${this.iconClass}`
        },
        svgClass() {
          if (this.className) {
            return 'svg-icon ' + this.className
          } else {
            return 'svg-icon'
          }
        },
        styleExternalIcon() {
          return {
            mask: `url(${this.iconClass}) no-repeat 50% 50%`,
            '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
          }
        }
      }
    }
    </script>
    
    <style scoped>
    .svg-icon {
      width: 1em;
      height: 1em;
      vertical-align: -0.15em;
      fill: currentColor;
      overflow: hidden;
    }
    
    .svg-external-icon {
      background-color: currentColor;
      mask-size: cover!important;
      display: inline-block;
    }
    </style>
  • 实际使用svg组件

    首先是将svg图标放在assets/icons/svg目录中,因为main上面的路径是如此,你也可以更改
    然后在其他组件中使用:
    <svg-icon :icon-class="svgName"/>
    svgName图标的名字,将参数传递到封装好的svg组件中即可,:class-name属性可有可无,可不传。
  • 文章与资源

vue使用elementUI分页组件

  • 先来看看main.js中引入分页组件

    // 分页组件
    import Pagination from "@/components/Pagination";
    
    // 全局组件挂载
    Vue.component('Pagination', Pagination)
  • 若依封装的Pagination组件

    <template>
      <div :class="{'hidden':hidden}" class="pagination-container">
        <el-pagination
          :background="background"
          :current-page.sync="currentPage"
          :page-size.sync="pageSize"
          :layout="layout"
          :page-sizes="pageSizes"
          :pager-count="pagerCount"
          :total="total"
          v-bind="$attrs"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        />
      </div>
    </template>
    
    <script>
    //滚动工具类,详情见本节最下方文章与资源
    import { scrollTo } from '@/utils/scroll-to'
    
    export default {
      name: 'Pagination',
      props: {
        total: {
          required: true,
          type: Number
        },
        page: {
          type: Number,
          default: 1
        },
        limit: {
          type: Number,
          default: 20
        },
        pageSizes: {
          type: Array,
          default() {
            return [10, 20, 30, 50]
          }
        },
        // 移动端页码按钮的数量端默认值5
        pagerCount: {
          type: Number,
          default: document.body.clientWidth < 992 ? 5 : 7
        },
        layout: {
          type: String,
          default: 'total, sizes, prev, pager, next, jumper'
        },
        background: {
          type: Boolean,
          default: true
        },
        autoScroll: {
          type: Boolean,
          default: true
        },
        hidden: {
          type: Boolean,
          default: false
        }
      },
      computed: {
        currentPage: {
          get() {
            return this.page
          },
          set(val) {
            this.$emit('update:page', val)
          }
        },
        pageSize: {
          get() {
            return this.limit
          },
          set(val) {
            this.$emit('update:limit', val)
          }
        }
      },
      methods: {
        handleSizeChange(val) {
          this.$emit('pagination', { page: this.currentPage, limit: val })
          if (this.autoScroll) {
            scrollTo(0, 800)
          }
        },
        handleCurrentChange(val) {
          this.$emit('pagination', { page: val, limit: this.pageSize })
          if (this.autoScroll) {
            scrollTo(0, 800)
          }
        }
      }
    }
    </script>
    
    <style scoped>
    .pagination-container {
      background: #ffffff;
      padding: 32px 16px;
    }
    .pagination-container.hidden {
      display: none;
    }
    </style>
  • 实际使用分页组件

    <pagination
      v-show="total>0"
      :total="total"
      :page.sync="queryParams.pageNum"
      :limit.sync="queryParams.pageSize"
      @pagination="getList"
    />
    
    //在其他组件中直接使用分页组件,.sync是双向绑定修饰符,使子组件数据与父组件数据双向绑定
  • 文章与资源

created中异步获取数据问题

在写项目的时候,我常常遇到这种情况,在created钩子函数中请求第三方数据,并将数据存入data中
然后在mounted函数中,拿到数据进行一些操作,但是实验后发现mounted函数中并不能拿到数据,
当即就猜到应该mounted函数在执行的时候,created函数的异步请求还没有完成,那有什么好的办法呢?

  • 第一种方式就是在mounted中设置一个定时器,等到一定时间执行定时器函数拿数据
    这种方式不好的地方在,你没办法准确知道等待多长时间,异步请求的时间是不确定的,这种方式不推荐
  • 第二种方式是使用watch监听数据变化,一旦异步请求完毕,则数据发生变化,则watch监听到数据变化后
    就可以在watch函数中对Dom进行一些操作了

文章推荐

vue中引用图片

记录一下vue中引用图片和css中引用图片,有时候经常忘记

  • vue中引用图片
    <img src="@/assets/images/qrcode.png" style="text-align:center;"/>
  • css引用图片
    background-image: url("~@/assets/images/loginbg3.jpg");

若依中使用的插件

若依前端中配置了几个自定义的插件,这里主要讲两个插件,一个是缓存的插件,一个是模态框的插件

  • 缓存插件
    缓存插件是若依为了方便操作sessionStorage和localStorage所做的封装

    • 首先来看看main.js中

      import plugins from './plugins' //自定义插件
      
      //进入./plugins/index.js插件函数,这里将封装好的缓存对象绑定到了vue的原型对象中,这样在任何组件中都可以使用了
      import tab from './tab'
      import auth from './auth'
      import cache from './cache'
      import modal from './modal'
      import download from './download'
      
      export default {
        install(Vue) {
          // 页签操作
          Vue.prototype.$tab = tab
          // 认证对象
          Vue.prototype.$auth = auth
          // 缓存对象
          Vue.prototype.$cache = cache
          // 模态框对象
          Vue.prototype.$modal = modal
          // 下载文件
          Vue.prototype.$download = download
        }
      }
    • 再进入./cache.js看看具体实现吧

      const sessionCache = {
        set (key, value) {
          if (!sessionStorage) {
            return
          }
          if (key != null && value != null) {
            sessionStorage.setItem(key, value)
          }
        },
        get (key) {
          if (!sessionStorage) {
            return null
          }
          if (key == null) {
            return null
          }
          return sessionStorage.getItem(key)
        },
        setJSON (key, jsonValue) {
          if (jsonValue != null) {
            this.set(key, JSON.stringify(jsonValue))
          }
        },
        getJSON (key) {
          const value = this.get(key)
          if (value != null) {
            return JSON.parse(value)
          }
        },
        remove (key) {
          sessionStorage.removeItem(key);
        }
      }
      const localCache = {
        set (key, value) {
          if (!localStorage) {
            return
          }
          if (key != null && value != null) {
            localStorage.setItem(key, value)
          }
        },
        get (key) {
          if (!localStorage) {
            return null
          }
          if (key == null) {
            return null
          }
          return localStorage.getItem(key)
        },
        setJSON (key, jsonValue) {
          if (jsonValue != null) {
            this.set(key, JSON.stringify(jsonValue))
          }
        },
        getJSON (key) {
          const value = this.get(key)
          if (value != null) {
            return JSON.parse(value)
          }
        },
        remove (key) {
          localStorage.removeItem(key);
        }
      }
      
      export default {
        /**
         * 会话级缓存
         */
        session: sessionCache,
        /**
         * 本地缓存
         */
        local: localCache
      }
    • 最后看看实际使用吧

      saveSetting() {
          this.$modal.loading("正在保存到本地,请稍候...");
          this.$cache.local.set(    //保存到了localStorage中
              "layout-setting",
              `{
              "topNav":${this.topNav},
              "tagsView":${this.tagsView},
              "fixedHeader":${this.fixedHeader},
              "sidebarLogo":${this.sidebarLogo},
              "dynamicTitle":${this.dynamicTitle},
              "sideTheme":"${this.sideTheme}",
              "theme":"${this.theme}"
              }`
          );
          setTimeout(this.$modal.closeLoading(), 1000)
      }
  • 模态框插件
    模态框指的是当用户在页面进行某些操作时,系统弹出提示,消息,确认框,来看看若依中是如何设计的吧

    • 还是进入main.js中

      import plugins from './plugins' //自定义插件
      
      //进入./plugins/index.js插件函数,这里将模态框对象绑定到了vue的原型对象中,这样在任何组件中都可以使用了
      import tab from './tab'
      import auth from './auth'
      import cache from './cache'
      import modal from './modal'
      import download from './download'
      
      export default {
        install(Vue) {
          // 页签操作
          Vue.prototype.$tab = tab
          // 认证对象
          Vue.prototype.$auth = auth
          // 缓存对象
          Vue.prototype.$cache = cache
          // 模态框对象
          Vue.prototype.$modal = modal
          // 下载文件
          Vue.prototype.$download = download
        }
      }
    • 再进入modal.js文件中看看吧,这里其实封装了elementUI的模态框

      import { Message, MessageBox, Notification, Loading } from 'element-ui'
      
      let loadingInstance;
      
      export default {
        // 消息提示
        msg(content) {
          Message.info(content)
        },
        // 错误消息
        msgError(content) {
          Message.error(content)
        },
        // 成功消息
        msgSuccess(content) {
          Message.success(content)
        },
        // 警告消息
        msgWarning(content) {
          Message.warning(content)
        },
        // 弹出提示
        alert(content) {
          MessageBox.alert(content, "系统提示")
        },
        // 错误提示
        alertError(content) {
          MessageBox.alert(content, "系统提示", { type: 'error' })
        },
        // 成功提示
        alertSuccess(content) {
          MessageBox.alert(content, "系统提示", { type: 'success' })
        },
        // 警告提示
        alertWarning(content) {
          MessageBox.alert(content, "系统提示", { type: 'warning' })
        },
        // 通知提示
        notify(content) {
          Notification.info(content)
        },
        // 错误通知
        notifyError(content) {
          Notification.error(content);
        },
        // 成功通知
        notifySuccess(content) {
          Notification.success(content)
        },
        // 警告通知
        notifyWarning(content) {
          Notification.warning(content)
        },
        // 确认窗体
        confirm(content) {
          return MessageBox.confirm(content, "系统提示", {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: "warning",
          })
        },
        // 提交内容
        prompt(content) {
          return MessageBox.prompt(content, "系统提示", {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: "warning",
          })
        },
        // 打开遮罩层
        loading(content) {
          loadingInstance = Loading.service({
            lock: true,
            text: content,
            spinner: "el-icon-loading",
            background: "rgba(0, 0, 0, 0.7)",
          })
        },
        // 关闭遮罩层
        closeLoading() {
          loadingInstance.close();
        }
      }
    • 最后看看实际使用吧

      /** 强退按钮操作 */
      handleForceLogout(row) {
        this.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function(){
          return forceLogout(row.tokenId);
        }).then(() => {
          this.getList();
          this.$modal.msgSuccess("强退成功");
        }).catch(() => {});
      }
      
      saveSetting() {
          this.$modal.loading("正在保存到本地,请稍候...");
          this.$cache.local.set(
              "layout-setting",
              `{
              "topNav":${this.topNav},
              "tagsView":${this.tagsView},
              "fixedHeader":${this.fixedHeader},
              "sidebarLogo":${this.sidebarLogo},
              "dynamicTitle":${this.dynamicTitle},
              "sideTheme":"${this.sideTheme}",
              "theme":"${this.theme}"
              }`
          );
          setTimeout(this.$modal.closeLoading(), 1000)
      }

路由传参后,页面刷新数据消失问题

在写项目的过程中,碰到这种情况,当我进行路由跳转传参时,在新的页面中再一次刷新后,新页面中的数据没了
因为数据是跳转页面时传递过来的,所以当你刷新时,没有参数传递自然在新页面中没有数据了
以下是解决办法:

  • 使用query代替params

    //这种方式是不行的,对了参数尽量都是字符串而不是数字,例如arr中,否则有警告
    this.$router.push({name:"Essay",params:{id:"1024",name:"万一",arr:[1,2,3,4,5]}})
    
    //这种方式可以,因为在页面跳转时,参数会拼接在url中,再次刷新页面后,url依然有参数,所以数据依然存在
    this.$router.push({path:"/front/kepu/essay",query:{id:"1024",name:"万一"}})
  • 依然使用query,不同的是:传递参数时,将参数序列化

    //传递参数
    this.$router.push({path:"/front/kepu/essay",
                       query:{data:JSON.stringify({id:"1024",name:"万一",data:{a:"b"}})}})
    
    //接收参数,也可以将数据存到data的变量中
    {{JSON.parse($route.query.data).id}}
    {{JSON.parse($route.query.data).name}}
    {{JSON.parse($route.query.data).data.a}}

    第二种方式解决的是,当传递参数时,参数包含对象或数组时(例如data),url会强制将data参数序列化
    这使得采用第一种方式的话,再次刷新页面,依然丢失数据,所以第二种是对第一种方式的改进。
    不过这上面两种方式都不太好,因为url有长度限制,如果参数是非常大的对象,url参数拼接将超过长度
    这时再次刷新页面还是会失败。

  • 使用动态路由来传递参数

    // 路由配置
    {
       path:'/detail/:id',
       name:'detail',
       component:Detail,
       props:true             // 如果props设置为true,$route.params将被设置为组件属性  
    }
     
    // 路由跳转
    this.$router.push({
       path:`/detail/${id}`
    })
     
    // 详情页获取参数
    export default {
      props:['id'],      // 将路由中传递的参数id解耦到组件的props属性上
      mounted(){
        console.log("id",this.id);  
      }
    }

    这种方式进行路由传参,页面刷新后,依然有数据,不过也只适合传递短数据

  • 使用cookie或者sessionStorage传递参数
    这种方式适合大数据存放参数,没有实验,但应该没问题。

文章推荐:

其他

  • 当路由跳转时,在front目录下同时有index目录(该目录下同时存在index.vue)和index.vue时,
    你的路由路径写成:(resolve) => require(['@/views/front/index'], resolve)
    route-view会显示front目录的index.vue文件,而不会显示front目录中index目录下的index.vue文件

    这个小问题刚开始把我整懵逼了,我要跳转到front目录下的index目录中的index.vue文件
    但是像上面写只会跳转到front目录下的index.vue文件。

  • a标签包裹其他标签时,需要去掉a标签下划线,并且指定固定颜色,不然有些链接点击后,会变颜色

    text-decoration: none;
    color: #333;
  • js代码debug
    在想要暂停的地方写:debugger

  • vue引入echarts5和echarts4版本的不同

    //echarts4的引入
    import echarts from 'echarts'
    Vue.prototype.$echarts = echarts
    
    //echarts5的引入
    import * as echarts from 'echarts'
    Vue.prototype.$echarts = echarts
  • 文章推荐