element-ui 分页输入框回车与页面查询中的 @keyup.enter事件冲突
参考: https://blog.csdn.net/u012138137/article/details/88549019
vue自定义指令实现按钮权限管理
参考: https://segmentfault.com/a/1190000037624635
$bus使用
bus主要是解决无关系组件之间的交互问题, 另外一种解决无关系组件间的交互问题就是使用vuex,也很方便。
参考: https://www.cnblogs.com/fqh123/p/12704910.html
vue 实现复制到粘贴板功能
参考: https://blog.csdn.net/qq_36437172/article/details/87449165
Sortablejs ElementUI el-table 实现拖拽之后影响文字选中复制
参考: https://blog.csdn.net/weixin_43861299/article/details/112217154
element-ui表单验证的几种方法
参考: https://www.jianshu.com/p/d9c88d6ab439
使用FormData对象发送文件
报错: request to https://registry.cnpmjs.org/vue failed, reason: Hostname/IP does not match certificate‘s
命令行执行: npm config set strict-ssl false
参考了: https://blog.csdn.net/qq_39378657/article/details/107550663
-S, -D, -g
-S -save 的缩写 用于生产(上线)环境下,包名会被注册在package.json的dependencies里面,在生产环境下这个包的依赖依然存在;
-D -dev(生产) 包名会被注册在package.json的devDependencies里面,仅在开发环境下存在的包用-D,如babel,sass-loader这些解析器
devDependencies ,是我们开发的时候需要用到的一些包,只需要用于开发阶段,真正打包上线的时候并不需要这些包,因为这些工具只是你用来打包代码的,是用来识别特定文件以及代码,帮助我们生产最终文件的
dependencies,这个则是需要发布到生产环境中的,就比如你要跑一个基于vue的项目,所以需要vue.js来支持,而这个vue.js文件就需要跟随项目到最终的生产环境
-g 是全局安装
**注意:**在使用npm install一个插件的时候,需要添加上-s或-d,不然不会再package.json中显示
把异步调用转换为同步调用
常规异步调用:
同步调用写法:
遍历对象,取几个key和value组成类数组
clear:both
参考: https://blog.csdn.net/liulanzaijia/article/details/87725232
BFC
参考: https://www.jianshu.com/p/0d713b32cd0d
vue业务组件按需加载
参考了: https://segmentfault.com/q/1010000017223459
报错: Unknown custom element: <> - did you register the component correctly? For recursive .... (很可能是因为相同组件被循环引用了)
const banAddUpdateDialog = import('@/views/musicContentService/bannerMgmt/banAddUpdateDialog')
<!-- 广告新增和修改弹窗 -->
<ban-add-update-dialog
v-if="loadAddBanner"
:dialog-title="$t('add_banner')"
:ban-operater-type="banOperaterType"
:add-update-visible="addUpdateVisible"
:ban-row-data="banRowData"
:page-type="pageType"
:project-list="projectList"
@close-or-open-dialog="addUpdateShow"
@reload-banner-list="query"
></ban-add-update-dialog>
防抖和节流
参考: https://www.cnblogs.com/fsg6/p/13305649.html
1. 事件频繁触发可能造成的问题?
1). 一些浏览器事件:window.onresize、window.mousemove等,触发的频率非常高,会造成浏览器性能问题
2). 如果向后台发送请求,频繁触发,对服务器造成不必要的压力
2. 如何限制事件处理函数频繁调用
1). 函数节流
2). 函数防抖
3. 函数节流(throttle)
1). 理解:
在函数需要频繁触发时: 函数执行一次后,只有大于设定的执行时间后才会执行第二次
适合多次事件按时间做平均分配触发
2). 场景:
窗口调整(resize)
页面滚动(scroll)
DOM 元素的拖拽功能实现(mousemove)
抢购疯狂点击(click)
4. 函数防抖(debounce)
1). 理解:
在函数需要频繁触发时: 在规定时间内,只让最后一次生效,前面的不生效。
适合多次事件一次响应的情况
2). 场景:
输入框实时搜索联想(keyup/input)
reduce用法
参考: https://www.cnblogs.com/fsg6/p/13360593.html
axios拦截器
参考: https://www.cnblogs.com/fsg6/p/13299669.html
进度条NProgress使用
参考: https://www.cnblogs.com/fsg6/p/13300521.html
深入浅出Object.defineProperty()
参考: https://www.cnblogs.com/fsg6/p/14472003.html
vs code中快捷键
ctrl + Enter 直接下一行开始编辑
element-ui 行点击
参考了: https://blog.csdn.net/weixin_44356647/article/details/105297035
rowClick (row) {
// 先判断已选中数据中是否有这行数据
let index = this.selectData.findIndex(item => {
return item.commentID == row.commentID
})
if (index == '-1') {
this.$refs['commonTable'].$refs['multipleTable'].toggleRowSelection(row, true) // 设置复选框为选中状态
} else {
this.$refs['commonTable'].$refs['multipleTable'].toggleRowSelection(row, false) // 设置复选框为非选中状态
this.selectData.splice(index, 1)
}
}
element-ui 解决el-table表格错位问题
参考了: https://blog.csdn.net/qq_35432904/article/details/110181982
this.$nextTick(() => {
this.$ref.commonTable.doLayout()
})
get,post接口api中统一写法
api中写法:
export const postRequest = (params, url, vm) => {
return axios.request({
url: url,
method: 'post',
headers: {
'Content-Type': 'application/json'
},
data: params
}, vm)
}
export const getRequest = (params,url, vue) => {
return axios.request({
url: url,
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
params: params
}, vue)
}
.vue文件中统一写法:
postRequest(
params,
'/music-userbehavior-service/v1/mgmt/playlist/updatevalidate',
this
).then(.....)
遍历json数据
过滤有key但value为空的键值对
let extendInfo = {
aa: '11',
bb: '哈哈',
cc: '',
dd: [{ff: 123, hh: 456}],
ee: []
}
console.log('extendInfo:', extendInfo);
let extendInfoParam = {}
for (let i in extendInfo) {
console.log(i, extendInfo[i], extendInfo[i].length, typeof(extendInfo[i]));
if((extendInfo[i] && typeof(extendInfo[i]) == 'string') || (extendInfo[i] && typeof(extendInfo[i]) == 'object' && extendInfo[i].length > 0)) {
extendInfoParam[i] = extendInfo[i]
}
}
console.log('extendInfoParam:', extendInfoParam);
Promise 多层级联调用接口写法
let P1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('passDataToP2')
},2000)
})
let P2 = P1.then(value1 => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('value1:', value1); // 打印出 passDataToP2
resolve('passDataToP3')
},2000)
})
})
let P3 = P2.then(value2 => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('value2:', value2); // 打印出 passDataToP3
resolve('passValue')
},2000)
})
})
P3.then((value3) => {
console.log('value3:', value3); // 打印出 passValue
})
Vue2与Vue3对比
Vue2中: 通过使用 Object.defineProperty 来劫持对象属性的 geter 和 seter 操作,当数据发生改变发出通知
Object.defineProperty(obj, 'prop', {
get: function () {
return val;
},
set: function (newVal) {
val = newVal;
document.getElementById('text').innerHTML = val;
}
});
document.addEventListener('keyup', function (e) {
obj.prop = e.target.value;
});
Vue3中: 通过ES6的新特性proxy来劫持数据,当数据改变时发出通知
var obj1 = new Proxy(obj, {
// target就是第一个参数obj, receive就是返回的obj(返回的proxy对象)
get: function (target, key, receive) {
// 返回该属性值
return target[key];
},
set: function (target, key, newVal, receive) {
// 执行赋值操作
target[key] = newVal;
document.getElementById('text').innerHTML = target[key];
}
})
document.addEventListener('keyup', function (e) {
obj1[0] = e.target.value;
});
使用Proxy优势:
1. 可直接监听数组类型的数据变化 (Vue2.x版本中的双向绑定不能检测到下标的变化,即不能检测数组地变化)
2. 监听的目标为对象本身,不需要像Object.defineProperty一样遍历每个属性,有一定的性能提升
3. 可拦截apply、ownKeys、has等13种方法,而Object.defineProperty不行
4. proxy可以劫持整个对象,并返回一个新对象直接实现对象属性的新增/删除
this.$set
数组中值改变,很可能驱动不了视图
采用this.$set来修改
组件间通信
1. props/$emit
2. $children/$parent
3. provide/reject
4. ref
5. eventBus
6. Vuex
7. $attrs/$listeners
首屏性能优化
参考: http://3ms.huawei.com/km/blogs/details/9720997
1. CDN引入
2. 按需引入
3. 懒加载
4. 开启gzip压缩
5. 关闭sourcemap文件打包
对于较低版本webpack,修改配置如下
module.exports = {
......
// 关闭 sourcemap
productionSourceMap: false,
......
}
路由
route: 路由. 对象. 三个属性: path,name,component.
routes: 路由表. 数组. 元素为route.
router: 路由器. 对象. 管理routes.
router组件安装完成,会注册两个全局组件:
<router-view> 定义显示部分,显示的是当前路由地址所对应的内容. 默认是 path: '/' 组件.
<router-link> 定义点击部分,属性to,即点击之后跳转到哪个路由地址.
Vue cnblogs学习
参考: https://www.cnblogs.com/wangyueping/category/1537282.html
前端下载模板
<el-button
v-show="sourceTypeValue === '1' && rowData.poolType === '107'"
size="small"
type="primary"
class="btn-margin"
>
<a class="a-link-class" href="../template/batchOutPoolTemplate.xlsx" download="batchOutPoolTemplate.xlsx">{{$t('batchOutPoolTemplate')}}</a>
</el-button>
element-ui el-date-picker 时间修改不了
change事件触发不了
参考了: https://blog.csdn.net/qq_39942621/article/details/114869209
参考了: https://blog.csdn.net/weixin_43953518/article/details/120507441
element-ui 时间控件,点击时间没有显示时间?
热门视频模块中是,没有先在data中定义这个时间,而是后来通过接口赋值导致的.
按理说,不应该动态给data添加新的属性,不然组件不能及时动态响应.
.splice批量插入数据
将上锁的数据按固定排序插进未锁的数据中:
let dataArr1 = [] // 状态为现网且未锁的数据
let dataArr2 = [] // 状态为现网且上锁的数据
dataArr2.forEach(item => {
dataArr1.splice(item.orderID - 1, 0, item)
})
this.$refs获取为undefined
参考了: https://www.cnblogs.com/henuyuxiang/p/15165784.html
临时解决办法:
setTimeout(() => {
this.$refs.regionInfoRef.regionInfo.regionModel = 0
}, 0)
两个对象数组,根据某个值,找出没有的项,push进table中
let temp = this.isAutomaticArr.filter(item => !res.data.charts.some(a => a.chartID === item.chartID))
if (temp && temp.length > 0) {
temp.forEach(item => {
this.contentTableData.push({
...item,
editFlag: false
})
})
}
获取两个数组的差集
Vuex顺序
使用mapState、mapGetters、mapMutations、mapActions
位置及顺序:
computed: {
...mapState({
}),
...mapGetters({
}),
// 其他computed
},
methods: {
...mapMutations({
}),
...mapActions({
}),
// 其他methods
}
网络请求放在methods最后面
methods: {
// mapMutations
// mapActions
// 其他methods
// 网络请求
}
生命周期钩子 (按照它们被调用的顺序)
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
指令缩写
用 : 表示 v-bind: 、用 @ 表示 v-on: 和用 # 表示 v-slot:
组件顶部要写组件说明,方便其他人理解
<!--
组件名:TempVue
功能:这是一个说明Vue模板功能的文件
责任人:
创建时间:
-->
<template>
<div class="temp-vue"></div>
</template>
<script>
export default {
name: 'TempVue',
data () {
return {}
}
}
</script>
<style lang="scss" scoped>
. temp-vue { }
</style>
CSS中 当长度为 0 时须省略单位
bad:
.class-1{
padding: 0px 5px;
border:0px solid #000;
}
good:
.class-1{
padding: 0 5px;
border:0;
}
选择器优化
优先使用class选择器,尽量不使用id选择器、通配符选择器、标签选择器,避免效率低选择器限制效率高选择器
Google 资深web开发工程师 Steve Souders 对 CSS 选择器的执行效率从高到低做了一个排序:
1.id选择器(#myid)(不要使用)
2.类选择器(.myclassname)
3.标签选择器(div,h1,p)
4.相邻选择器(h1+p)
5.子选择器(ul < li)
6.后代选择器(li a)
7.通配符选择器(*)
8.属性选择器(a[rel=“external”])
9.伪类选择器(a:hover, li:nth-child)
Vue 如何实现组件通信
A->B->C
->D
A 和 B、B 和 C、B 和 D 都是父子关系,C 和 D 是兄弟关系,A 和 C 是隔代关系(可能隔多代)
props/$emit:
父组件 A 通过 props 的方式向子组件 B 传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现。
$parent / $children与 ref:
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
$parent / $children:访问父 / 子实例
兄弟通信:
Bus;Vuex
跨级通信:
Bus;Vuex;provide / inject API、attrs/attrs/listeners
watch与computed
watch可用于监听数据的变化进而触发函数.
computed为计算属性,会根据数据的变化实时返回对应的数据.
computed对数据进行转化,原数据不会改变,使用watch和computed有时能达到同样的效果,
但是computed的性能要更高一些.
参考: https://www.cnblogs.com/gunelark/p/8492468.html
element ui dialog 关闭时调用了两次接口
原因是,点击footer中按钮返回,触发了dialog右上角的×close事件,
解决办法是,把footer中的click方法改成@click="dialogVisible = false"就行了
另外右上角的 × close事件为 @close="closeDialog" ,
如果采用 @closed="closeDialog",则导致可能出现不能直接点击 × 来关闭弹窗
一个最简单的按钮权限
main.js 中:
Vue.directive('permission', {
// 当被绑定的元素插入到 DOM 中时
inserted: (el, binding, vnode) => {
console.log(el)
console.log(binding)
console.log(vnode)
const aaa = false // 这里通过true和false来控制权限
if(!aaa) {
el.parentNode.removeChild(el)
}
}
})
类数组升序排序
this.contentTableData.sort((a, b) => { return a.orderID - b.orderID })
空数组的 find(),filter() 等方法都会报错
根据某个相同值,合并两个类数组
// 先生成一个需要和 tableData 合并的类数组
let tempArr = res.data.poolRelationModels.map(item => {
return {
songCode: item.contentCode || '', // 歌曲编码
relationStatus: item.status || '', // 池子关联状态
relationIsautomatic: item.isautomatic || '', // 加入方式
relationCreateTime: item.createTime || '', // 创建时间
relationContentScore: item.contentScore || '', // 评分
relationContentRank: item.contentRank || '' // 名次
}
})
this.tableData = this.tableData.reduce((acc, cur) => {
let target = acc.find(e => e.songCode === cur.songCode)
if (target) {
Object.assign(target, cur)
} else {
acc.push(cur)
}
return acc
}, tempArr)
按回车键搜索
document.onkeydown = (e) => {
let key = window.event.keyCode
if (key === 13) {
this.query()
}
}
类数组去重
this.selectedTagsData = Array.from(new Set([...this.leftTreeData, ...this.rightTreeData]))
const arr = [...tableCodes, ...codes] // 合并两个数组
const relatedSongs = Array.from(new Set(arr)) // 去重
对象中key为变量,采用 [ ] 的形式进行赋值
VS Code中断点调试
下载插件 -- Code Debugger 和 Debugger for Chrome
然后运行程序,在Debug中再运行下就后跳进Vs Code中的断点.
也可以直接在浏览器中调试,在需要的地方写一个log,方便再浏览器中通过log调到对应.vue文件的方法中
Eslint不起作用,报Eslint不能格式化 .vue文件
首先在控制台OUTPUT中能看到错误.
缺少了eslint utils 包,从其他地方拷进node_modules中就可以了
图片悬浮放大
img {
width: 50px;
height: 50px;
vertical-align: middle;
transition:all .8s;
-moz-transition:all .8s;
-webkit-transition:all .8s;
-o-transition:all .8s;
}
img:hover {
transform:scale(5, 5) translate(20px,0px);
position: fixed;
z-index: 1;
}
Vue.$nextTick(() => { })
this.$nextTick(() => {
...
})
改变数据之后,主动刷新下页面. 避免修改了数据却没有更新到DOM上
(Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。
$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM)
Vue.set( target, propertyName/index, value )
this.$set(this.queryConditions, 'status', '1')
向响应式对象中添加一个property, 并确保这个新property 同样是响应式的,且触发视图更新.
生命周期 activated和deactivated
activated 被 keep-alive 缓存的组件激活时调用。每次切换回来都会执行, 区别于created和mounted是来回切换页面只调用一次
deactivated 被 keep-alive 缓存的组件停用时调用。每次离开当前组件都会调用
(只有当组件在 <keep-alive> 内被切换,才会有activated 和 deactivated 这两个钩子函数)