近况
好久没写博客了,现在已经是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
在想要暂停的地方写:debuggervue引入echarts5和echarts4版本的不同
//echarts4的引入 import echarts from 'echarts' Vue.prototype.$echarts = echarts //echarts5的引入 import * as echarts from 'echarts' Vue.prototype.$echarts = echarts
文章推荐