el-table表格中实现动态添加输入框
利用vue的新特性,slot-scope来解决
<el-table-column prop="reportName" label="报告名称">
<template slot-scope="scope">
<el-input v-model="scope.row.reportName" @blur="confirmData" clearable></el-input>
</template>
</el-table-column>
Vue中引入插入图片方法
使用require引入图片路径
<img :src="item.url" class="item-img"/>
export default {
name: "SideBar",
data(){
return{
itemList: [
{name: 'temperature', title: '温、湿度', no: 1, url: require('../../assets/images/wenshidu-icon.png')},
]
}
}
}
Vue中引入背景图片方法
使用require引入背景图片路径,跟url拼接起来
<el-menu-item v-for="(item, index) in itemList" :key="index" :index="item.name" class="menu-item body-bgcolor" :style="{background: item.bgUrl}">
export default {
name: "SideBar",
data(){
return{
itemList: [
{'name': 'temperature', 'title': '温、湿度', 'bgUrl': 'url(' + require('../../assets/images/wenshidu-icon.png') + ')',},
]
}
}
}
el-menu设置默认选中项
使用自带的:default-active
<el-menu ref="sidebarMenu" class="menu" router :default-active="navSelected">
<el-menu-item></<el-menu-item>
</el-menu>
export default {
name: "SideBar",
data(){
return{
navSelected: 'temperature'
}
}
}
el-menu导航上下切换选中项
这个方法自己想的,主要是利用了route的meta属性,给每一项都设置了一个序号
{
name: 'functions',
path: '/functions',
component: () => import('@/views/module/functions'),
redirect: '/functions/temperature',
children: [
{
name: 'temperature',
path: '/functions/temperature',
component: () => import('@/views/module/functions/temperature'),
meta: {
title: '温、湿度',
no: 1
}
}]
}
<template>
<div class="side-bar">
<el-row span="24">
<el-menu ref="sidebarMenu" class="menu" router :default-active="navSelected">
<i class="up-button" @click="scrollUp"></i>
<el-menu-item v-for="(item, index) in itemList" :key="index" :index="item.name" :class="{'menu-item': true, 'body-bgcolor': true, 'active-state': no == item.no}">
<img :src="item.url" class="item-img"/>
<span slot="title" :class="item.name" >{{ item.title }}</span>
</el-menu-item>
<i class="down-button" @click="scrollDown"></i>
</el-menu>
</el-row>
</div>
</template>
export default {
name: "SideBar",
data(){
return{
no: 1,
navSelected: 'temperature',
itemList: [
{name: 'temperature', title: '温、湿度', no: 1, url: require('../../assets/images/wenshidu-icon.png')
}]
}
},
methods: {
scrollUp(){
console.log('当前no', this.$route.meta.no)
if(this.$route.meta.no !== 1){
console.log('切换上一项')
this.no = this.$route.meta.no - 1
this.changeFunction()
}
},
scrollDown(){
console.log('当前no', this.$route.meta.no)
if(this.$route.meta.no !== 8){
console.log('切换下一项')
this.no = this.$route.meta.no + 1
this.changeFunction()
}
},
changeFunction(){
console.log('切换功能')
let selectItem = this.itemList.find(item => item.no == this.no)
console.log('selectItem', selectItem)
let path = selectItem.name
console.log('path', path)
this.$router.push('/functions/' + path)
}
}
el-menu导航上下切换选中项(升级版:初始状态摆放不下全部的)
方法也是自己想的,通过不同状态下,调整整个导航的marginTop值,并且用v-if来控制元素的显示与隐藏
<template>
<div class="side-bar">
<el-row span="24" class="sidebar-wrap">
<!-- <i class="up-button" @click="scrollUp"></i>-->
<el-menu ref="sidebarMenu" class="menu" router :default-active="navSelected" :style="menuStyle">
<el-menu-item v-for="(item, index) in itemList" :key="index" :index="item.name" class="menu-item body-bgcolor" :class="{'active-state': no == item.no}"
:style="item.itemStyle" v-if="item.isShow">
<img :src="item.url" class="item-img"/>
<span slot="title" :class="item.name" >{{ item.title }}</span>
</el-menu-item>
</el-menu>
<!-- <i class="down-button" @click="scrollDown"></i>-->
</el-row>
</div>
</template>
<script>
export default {
name: "SideBar",
data(){
return{
no: 1,
navSelected: 'temperature',
menuStyle: '',
itemList: [
{name: '1', title: '1', no: 1, url: require('../../assets/images/1-icon.png'), itemStyle: {marginTop:'10px'}, isShow: true},
{name: '2', title: '2', no: 2, url: require('../../assets/images/2-icon.png'), itemStyle: {marginTop:'10px'}, isShow: true},
{name: '3', title: '3', no: 3, url: require('../../assets/images/3-icon.png'),itemStyle: {marginTop:'10px'}, isShow: true},
{name: '4', title: '4', no: 4, url: require('../../assets/images/4-icon.png'), itemStyle: {marginTop:'10px'}, isShow: true},
{name: '5', title: '5', no: 5, url: require('../../assets/images/5-icon.png'), itemStyle: {marginTop:'10px'}, isShow: true},
{name: '6', title: '6', no: 6, url: require('../../assets/images/6.png'), itemStyle: {marginTop:'10px'}, isShow: true},
{name: '7', title: '7', no: 7, url: require('../../assets/images/7.png'), itemStyle: {marginTop:'10px'}, isShow: true},
{name: '8', title: '8', no: 8, url: require('../../assets/images/8-icon.png'), itemStyle: {marginTop:'10px'}, isShow: true},
{name: '9', title: '9', no: 9, url: require('../../assets/images/9-icon.png'), itemStyle: {marginTop:'40px'}, isShow: true},
]
}
},
mounted(){
},
methods: {
scrollUp(){
console.log('当前no', this.$route.meta.no)
if(this.$route.meta.no !== 1){
console.log('切换上一项')
this.no = this.$route.meta.no - 1
this.changeFunction()
console.log('menuStyle', this.menuStyle)
if(this.$route.meta.no === 8 && this.menuStyle !== 0){
this.menuStyle = {marginTop: 0}
console.log('menuStyle', this.menuStyle)
}
// if(this.$route.meta.no === 9){
// this.itemList.forEach((item) => {
// if(item.no == 9){
// // item.itemStyle = {marginTop:'40px'}
// }else if(item.no == 1){
// item.isShow = true
// }
// })
// this.menuStyle = {marginTop:'10px'}
// }
if(this.$route.meta.no === 2){
this.itemList.forEach((item) => {
if(item.no == 9){
item.itemStyle = {marginTop:'10px'}
item.isShow = false
}else if(item.no == 1){
item.isShow = true
}
})
}
}
},
scrollDown(){
console.log('当前no', this.$route.meta.no)
if(this.$route.meta.no !== 9){
console.log('切换下一项')
this.no = this.$route.meta.no + 1
if(this.$route.meta.no === 8){
// this.menuStyle = {marginTop:'-110px'}
console.log('menuStyle', this.menuStyle)
this.itemList.forEach((item) => {
if(item.no == 9){
item.isShow = true
item.itemStyle = {marginTop:'10px'}
}else if(item.no == 1){
item.isShow = false
}
})
}
this.changeFunction()
}
},
changeFunction(){
console.log('切换功能')
let selectItem = this.itemList.find(item => item.no == this.no)
console.log('selectItem', selectItem)
let path = selectItem.name
console.log('path', path)
this.$router.push('/functions/' + path)
this.navSelected = path
}
}
}
</script>
<style scoped>
</style>
父组件调用子组件中的方法
在父组件中引入子组件,并且为子组件设置ref值,和id一样,调用时候直接用$refs获取子组件调用其方法
<i class="up-button" @click="scrollUp"></i>
<side-bar ref="navbar"></side-bar>
<i class="down-button" @click="scrollDown"></i>
scrollUp(){
this.$refs.navbar.scrollUp()
},
scrollDown(){
this.$refs.navbar.scrollDown()
}
利用路由实现子组件调用父组件的方法(路由可以当成组件使用props和$emit)
子组件:
this.$emit('unsolvedNum', this.unsolvedTableData.length)
父组件:
<router-view @unsolvedNum="updateNum"></router-view>
updateNum(num){
console.log('num', num)
this.num = num
},
解决el-table表格对不齐问题
/*解决表格对不齐问题*/
.el-table th.gutter{
display: table-cell !important;
}
隐藏(或设置)el-table表格滚动条
/*隐藏表格滚动条*/
.el-table__body-wrapper::-webkit-scrollbar{
width: 0; /*宽度为0隐藏*/
}
设置鼠标划过el-menu的选项时,和选中时的样式
.el-menu-item:hover,
.el-menu-item.is-active {
background: url('../../images/select-item-bg.png') no-repeat !important;
}
v-bind绑定的class和普通的类不冲突,默认的class会保留
<div class="title" :class="{'active': isActive, 'line': isLine}">Hello World</div>
.number是让输入框的值变成数字类型,.lazy当输入框失去焦点时更新数据
父组件调用子组件的方法时候,如果获取不到子组件可以尝试使用延时:原因是子组件的初始化操作还未完成
但是最好不要利用延时,因为你没法保证每次都能这个时间加载完成
父子组件的生命周期执行顺序如下:
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
<OnedayChart ref="oneday"></OnedayChart>
console.log('$refs', this.$refs)
console.log('oneday', this.$refs.oneday)
setTimeout(() => {
console.log('n$refs', this.$refs)
console.log('noneday', this.$refs.oneday)
}, 1000)
// this.$nextTick(() => {
// console.log('n$refs', this.$refs)
// console.log('noneday', this.$refs.oneday)
// })
el-dialog的弹窗的关闭按钮失效
尝试多次,再加上查看文档例子,终于找到了原因,将dialog放在里面了,需要将触发的地方,按钮或者其他放在dialog的外面
el-dialog弹窗被遮罩挡住
设置 append-to-body属性为true
<el-dialog title="修改密码" :visible.sync="dialogFormVisible" width="25%" append-to-body>
路由守卫和使用白名单
const whiteList = ['/index', 'test', 'login']
// 通过路由守卫阻止单点登录
router.beforeEach((to, from, next) => {
console.log('判断是否单点登录', to.path)
const username = sessionStorage.getItem('username')
if(!username){
if(whiteList.indexOf(to.path) !== -1){
console.log("白名单")
next()
}else{
Message.warning('请先登录后再操作')
next('/login')
}
}
next()
})
vue中使用全局变量
一般$root获取根节点的方式不推荐
在src目录下新建一个global文件夹,创建一个index.js文件,将需要使用的变量定义在里面
const keyOn = false
export default {
keyOn
}
在其他js或vue组件中引用时,导入进去
使用时注意是个对象,里面的值是属性
import global from '@/global'
global.keyOn = true
解决 cnpm : 无法加载文件 C:\Users\hp\AppData\Roaming\npm\cnpm.ps1,因为在此系统上禁止运行脚本
解决方式:
1、在系统中搜索框 输入 Windos PowerShell
2、点击“管理员身份运行”
3、输入“ set-ExecutionPolicy RemoteSigned”回车
4、根据提示,输入A,回车
5、再次回到cnpm -v执行成功
方法来自:https://blog.csdn.net/chengjingxuang123/article/details/105470815/
弹框后el-input自动聚焦
el-input文档中有autofocus属性,但是弹框后就不能自动聚焦了,初步看可能是el-input包裹着input,或者是弹框的遮罩,有时间研究看看原因
解决方案:利用js的focus方法
直接执行 this.$refs.input.focus()
可能会报错,因为元素未渲染完成
<el-input type="text" ref="tagInput" v-model="rfid"></el-input>
addTag(){
this.tagInfoVisible = true
this.$nextTick(() => {
this.$refs.tagInput.focus()
})
},
el-table翻页序号接着上一页
<el-table-column prop="NO" type="index" label="序号" width="50">
<template slot-scope="scope">
<span>{{(currentPage - 1) * pageSize + scope.$index + 1}}</span>
</template>
</el-table-column>
data(){
return {
currentPage: 1,
pageSize: 10
}
}
elementui阻止自带点击事件的组件事件冒泡
在该组件外面加一层div,@click.stop
<div @click.stop>
// replace(/[<br>]/g,'')是将所有<br>替换为空
<el-checkbox :label="field.colName.replace(/[<br>]/g,'')"></el-checkbox>
</div>
解决vuex页面刷新数据丢失问题
一种是存储时候利用sessionStorage,刷新时从sessionStorage取出再存入vuex中
另一种方法是
如果存储数据较少,可以在app.vue中添加
//===========================下面是解决刷新页面丢失vuex数据
created() {
//在页面加载时读取sessionStorage里的状态信息
if (sessionStorage.getItem('store')) {
this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem('store'))));
}
//在页面刷新时将vuex里的信息保存到sessionStorage里
window.addEventListener('beforeunload', () => {
sessionStorage.setItem('store', JSON.stringify(this.$store.state));
});
}
解决弹框表单提示验证错误
el-form中添加属性
:validate-on-rule-change="false" // 打开弹窗不进行表单验证
点击空白处关闭弹窗取消提示
active=‘cancel’说明点击的是取消按钮,active=‘close’说明点击的是空白处
this.$confirm('此操作将进行删除操作, 是否继续?', '提示', {
cancelButtonClass: "btn-custom-cancel",
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
distinguishCancelAndClose: true,
}).then(() => {
this.sendCommand(type)
}).catch(active => {
console.log(active)
if(active === 'cancel'){
this.$message({
type: 'info',
message: '已取消删除操作'
})
}
})
Js 修改对象数组里的对象属性名
// array为数组,old_name为修改前属性名,new_name为修改后属性名
JSON.parse(JSON.stringify(array).replace(/old_name/g, 'new_name'))
解释:
1、JSON.stringify() 把json对象 转成 json字符串
2、使用正则的 replace() 方法替换属性名
3、JSON.parse() 再把json字符串 转成 json对象
参考文章:
Js 修改对象数组里的对象属性名
el-input无法获取焦点
设置延时,时间可以为0
<el-input ref="fileName" v-model="fileName"></el-input>
setTimeout(() => {
this.$refs.fileName.focus()
},0)
合法文件名校验
check(){
let reg = new RegExp('[\\\\/:*?\"<>|]')
if (reg.test(this.fileName)) {
let flag = false
this.$message.error('文件名包含非法字符,请修改!')
return flag
}
}
隐藏滚动条
谷歌浏览器Chrome
ul::-webkit-scrollbar {
display: none;
}
火狐浏览器Firefox
overflow-y: scroll;
scrollbar-color: transparent transparent;
scrollbar-track-color: transparent;
-ms-scrollbar-track-color: transparent;
报错Cannot read property ‘getBoundingClientRect‘ of undefined
原因在移除监听器时没有加true参数
// 页面销毁前
beforeDestroy() {
window.removeEventListener('scroll', this.handleScroll, true)
},
参考:Cannot read property ‘getBoundingClientRect‘ of undefined
从一个数组中删除另一个数组方法
// 数组arr1中包含数组arr2
arr1 = arr1.filter((item) => {
return arr2.every(val => {
return item.id !== val;
})
})
对象数组去重方法
let obj = {}
this.warningList = newArr.reduce((item, next) => {
obj[next.happentime] ? '' : obj[next.happentime] = true && item.push(next);
return item
}, [])