iView + Vue 踩坑日记
递归对树形结构数据处理---js模糊查询
//递归对树形结构数据处理---js模糊查询 const rebuildData = (value, arr) => { let newarr = []; arr.forEach(element => { if (element.title.indexOf(value) > -1) { newarr.push(element); } else { if (element.children && element.children.length > 0) { const ab = rebuildData(value, element.children); const obj = { ...element, children: ab }; if (ab && ab.length>0) { newarr.push(obj); } } } }); return newarr; }; this.point_arr = rebuildData( this.pointname,this.point_arr);
DOM变动事件的用法
1. DOMSubtreeModified:在DOM结构中发生任何变化时触发; 2. DOMNodeInserted:在一个节点作为子节点被插入到另一个节点中时触发; 3. DOMNodeRemoved:在节点从其父节点中被移除时触发; 4. DOMNodeInsertedIntoDocument:在一个节点被直接插入文档中或者通过子树间接插入文档后触发。在DOMNodeInserted之后触发; 5. DOMNodeRemovedFromDocument:在一个节点被直接从文档中删除或通过子树间接从文档中移除之前触发。在DOMNodeRemoved之后触发。 6. DOMAttrModified:在特性被修改之后触发; 7. DOMCharacterDataModified:在文本节点的值发生变化的时候触发。 //监听盒子内容变化 this.$nextTick(()=>{ data.addEventListener("DOMCharacterDataModified", this.changedom); }) //https://blog.csdn.net/flyingpig2016/article/details/53677679/
js日期转年月日
var d = new Date(); var d2 = d.getFullYear() + "年"+ (d.getMonth() + 1) +"月"+ d.getDate() +"日"; alert("当前日期: :" + d2);
var _arr = ['旅行箱', '旅行箱', '小米', '大米']; var _res = []; // _arr.sort(); //排序很重要 for (var i = 0; i < _arr.length;) { var count = 0; for (var j = i; j < _arr.length; j++) { if (_arr[i] == _arr[j]) { count++; } } _res.push([_arr[i], count]); i += count; } //_res 二维数维中保存了 值和值的重复数 var _newArr = []; for (var i = 0; i < _res.length; i++) { // console.log(_res[i][0] + "重复次数:" + _res[i][1]); _newArr.push(_res[i][0] + 'x' + _res[i][1]); } console.log(_newArr);
v-for 的时候使用 v-model 快捷绑定变量
<div v-for="(list, i) in dataList" :key="i"> <span>{{item.title}}</span>
//这里v-model不能直接用list <input type="text" v-model="bindData[i]"> </div>
通过refs获取dom
this.$refs.[dom] //可以解析变量
禁止输入框复制、粘贴、剪切
<Input type="password" class="show_input" oncopy="return false" onpaste="return false" oncut="return false" v-model="loginForm.loginpwd" @keyup.enter.native="login_by_username('loginForm')" placeholder="请输入密码" /> //全局监听 键盘事件如 CTRL + C window.addEventListener('copy',this.inputHandle); window.addEventListener('paste',this.inputHandle); window.addEventListener('cut',this.inputHandle); inputHandle(){ let edit = document.querySelector(".show_input"); //禁止复制 edit.oncopy = function() { return false; }; //禁止粘贴 edit.onpaste = function() { return false; }; //禁止剪切 edit.oncut = function() { return false; }; },
防止输入框自动填充
<Input type="text" v-model.trim="userinfo.msgcode" class="input" placeholder="请输入短信验证码" readonly v-noFill //这两行一起的 /> directives: { // 防止input输入框自动填充 noFill: { inserted: el => { let inputEl = el.getElementsByTagName("input")[0]; if (inputEl) { inputEl.addEventListener("focus", () => { inputEl.removeAttribute("readonly"); }); inputEl.addEventListener("blur", () => { inputEl.setAttribute("readonly", "readonly"); }); } } } },
vue组件中的.sync修饰符使用
//===================================父组件 <template> <div> <Son :title="title" @update:title="title = $event" /> </div> </template> <script> import Son from "./Son"; export default { name: "Father", components: { Son, }, data() { return { title: "我是标题", }; }, }; </script> //===================================子组件 <template> <div class="son"> <h1>{{ title }}</h1> <p></p> <div class="btnGroup"> <Button type="primary" @click="updateTitle">修改标题</Button> </div> </div> </template> <script> export default { name: "Son", props: { title: { type: String, }, }, data() { return {}; }, methods: { updateTitle() { this.$emit("update:title", "新标题"); }, }, }; </script> :title.sync就是:title="title" @update:title="title= $event"的缩写。 注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”title + ‘!’” 是无效的)。 //===================================父组件 <template> <div> <Son :title="title" @update:title="title = $event" /> <Son :title.sync="title" /> //两种写法效果一致 </div> </template>
vue 表单验证
项目背景:找回密码的时候一个页面同时有手机和密保找回方式,每种方式又有步骤条组件,多个表单验证用了同一个验证方法,就会出现某一个表单的某一个字段没法验证,但是其他字段缺可以。 解决方法:就是因为v-if 的问题,用v-show问题就迎刃而解了。
vue 项目首页标题logo
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
v-for 同时循环两个数组
1 //obj为对象 arr为数组 2 <!--循环对象和数组--> 3 <div v-for="(item,key,index) in obj"> 4 <!--{{ key }} {{ index }}--> 5 {{ arr[index].name }} {{ item }} 6 </div> 7 <!--循环两个数组--> 8 <div v-for="(item, index) in arr"> 9 {{ item.name }} {{ arrs[index].text }} 10 </div> 11 <!--循环两个对象 不可行--> 12 <div v-for="(item,key,index) in obj"> 13 {{ item }} {{ objs[key].one }} 14 </div>
需求:组件自带的事件钩子函数,需要传自定义参数
解决方法:以Page分页组件的on-change事件举例 重写一个箭头函数进行传参
1 <div class="page" v-if="exam.type == 1"> 2 <Page 3 :total="exam.total" 4 @on-change="page => changePage(page, exam)" 5 :current="exam.page" 6 :page-size="exam.pageSize" 7 show-total 8 ></Page> 9 </div> 10 11 changePage(page, exam) { 12 console.log(page, exam); 13 },
总结一下 change 和 select 事件的区别
场景一 比如写回显功能的时候,原始数据发生变化就会自动触发change事件,用select事件最合适
场景二 数据实时性 select事件触发后获取到的响应式数据是上一次的,change事件触发后获取到的响应式数据是实时的
vue 日期转时间戳多八小时问题
//首先我是在写回显功能的时候才发现的这个问题,需要把获取到的时间戳转换成日期格式 给日期组件渲染 //中国标准时间转换为yyyy-MM-dd export const datetime_ymd = ms => { var date = new Date(ms); var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); if (month < 10) { month = "0" + month; } if (day < 10) { day = "0" + day; } return year + "-" + month + "-" + day; }; //一、这里吧时间戳(开始时间是从当前零点开始的)转换成日期格式 如2022-3-16 这个日期给日期组件渲染是没有问题的 //二、请求数据的时候需要在把日期转换成时间戳 //时间转化为时间戳 export const date_time = datestring => { var time = new Date(datestring).getTime() / 1000; return time; }; //三、这个格式的日期转成时间戳的时候就有问题了,结果就是时间戳多了八小时,因为日期在转时间戳的时候如果后面没有跟时分秒会默认加上八小时。
//(如果是2022/3/16 就不会加八小时,但是这个日期格式一般不用) //解决方法一、最简单用new Date(),本来日期组件的日期就是这个格式 new Date(e.endtime * 1000); //解决方法二、时间戳转日期的时候在后面加上时分秒 // 东八区时间差 let _timezone = 8; //目标时区时间,东八区 东时区正数 西市区负数 let _offset_GMT = new Date().getTimezoneOffset(); // 本地时间和格林威治的时间差,单位为分钟 let diffTime = _offset_GMT * 60 * 1000 + _timezone * 60 * 60 * 1000; //0 //中国标准时间转换为yyyy-MM-dd export const datetime_ymd = ms => { var date = new Date(ms + diffTime); var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); if (month < 10) { month = "0" + month; } if (day < 10) { day = "0" + day; } return year + "-" + month + "-" + day; };
如何写回显功能
//需要的参数都存到url
keepAlive(obj) {
let path = this.$route.path;
let query = this.$route.query;
let data = {
teacherid: obj.teacherid,
lsbid: obj.lsbid,
directorid: obj.directorid,
classid: obj.classid,
createtime: obj.createtime,
page: obj.page,
endtime: obj.endtime,
iscache: true
};
let form_data = JSON.stringify(data);
let newQuery = {
form_data
};
query = newQuery;
this.$router.replace({
path,
query
});
},
//获取url信息的时候就要注意,一定要写到created生命周期里
//如果在mounted里 此时vue已经渲染完成了再改变date里的值会再次出发视图更新
//如果需要子组件渲染url数据的话,可以把这个方法写到子组件里,不用再父向子传值,还有延迟的问题。
created() {
//获取url
if (this.$route.query.form_data) {
this.record = JSON.parse(this.$route.query.form_data);
}
},
下拉菜单
<Select :value="form_list.classid" style="width:160px;margin-left:10px;margin-right: 15px" placeholder="选择班级" @on-select="classidChange" > <Option v-for="item in classes_list" :value="item.classid" :key="item.classid" > {{ gradeName(item.gradeid) }}{{ item.classname }} </Option> </Select> //下拉菜单组件最好用@on-select 事件 //@on-change 在回显的时候deta值发生变化 有时候deta值会自动变成undefined
Vue 兼容ie 使用transpileDependencies
//node_modules里的依赖默认是不会编译的,会导致es6语法在ie中的语法报错,所以需要在vue.config.js中使用transpileDependencies属性配置node_modules中指定哪些文件夹或文件需要编译.
//在vue.config.js中
module.exports = {
transpileDependencies: ["v-calendar"], // 需要编译的依赖包名
}
全局监听事件
1、vm.$on( event, callback )
监听当前实例上的自定义事件。事件可以由vm.$emit触发。回调函数会接收所有传入事件触发函数的额外参数。
2、vm.$emit( event, […args] )
触发当前实例上的事件。附加参数都会传给监听器回调,如果没有参数,形式为vm.$emit(event)
3、vm.$off( [event, callback] )
移除自定义事件监听器。
如果没有提供参数,则移除所有的事件监听器;
如果只提供了事件,则移除该事件所有的监听器;
如果同时提供了事件与回调,则只移除这个回调的监听器。
在main.js 中 window.myevent = new Vue(); 定义全局事件
window.myevent.$emit("class_report_reload",""); 发起事件第一个参数是 事件,第二个参数是值
在mounted 监听window.myevent.$on("class_report_reload",()=> {
this.init();
});
最后一定要移除事件,否则再次渲染该事件会被重复监听
如果页面显示的数据为对象时如何判断是否有数据
v-if="Object.keys(rawdara).length > 0"
Object.keys()方法会返回一个由给定对象的自身可枚举属性组成的数组
let person = {name:"张三",age:25,address:"深圳",getName:function(){}}
Object.keys(person) // ["name", "age", "address","getName"]
父组件传给子组件的对象,如果子组件更改了对象值的话,即使没有传值给父组件也会影响到父组件里的对象数据
//可使用深拷贝
let form_log = JSON.parse(JSON.stringify(this.form_log));
强制刷新组件之$forceupdate、v-if、key属性三种方式的适用
//1.$ forceupdate()仅针对当前组件以及其插槽相关子组件。 作用:例如当data中的某个内容进行了改变,但是页面没有进行实时的刷新,而我又通过打印能确定数据确实改变了,因此可以使用$ forceupdate()来迫使当前组件刷新。 //2.v-if通过变量控制的形式,可以触发 被控制的组件 beforeCreate、created、beforeMount、mounted、beforeDestroy、destroyed 这6个生命周期,但是由于v-if指令的原因,会导致其控制的内容会发生显示与隐藏操作。虽然可以达到刷新的效果,但是把其当作刷新这个功能,在项目中还是比较少见的。 //3.通过key属性来进行刷新操作,在web中的效果是最理想的,因为页面根本感觉不到组件的销毁与创建过程,但是确实满足了组件的刷新功能。 操作方式:在data中定义某个变量,然后将该变量放置在组件的key属性中,要实现该组件刷新时,只需改变变量的值即可。 注意:当key值改变的时候,child子组件实际上经历了新的child的创建过程以及旧的child的销毁过程 <template> <child ref="child1" :key='indexKey'></child> </template> <script> import child from "./child"; export default { components: { child }, data() { return { indexKey: 0 // 只需要通过操作如点击事件改变这个值,child子组件就会刷新,而且视觉上不会有变化 }; }, } </script>
if语句扩展
v-if="(info_details.resourceclass == 1 ||
info_details.resourceclass == 2) &&
info_details.converted == 1
"
三木运算符
:class="[isCollapsed ? 'hideIcon' : 'home']"
:class="['group_name', classdisabled ? 'class-disabled' : '']"
:class="[ 'user-info-title',chatItem.userid == sectionInfo.teacherid
? 'theme_color': '']"
:class="{ 'ivu-layout-sider-active': isCollapsed }" //如果后面的变量成立,类名生效
:class="[
pen.className, //变量也是可以被解析成类名的 pen.className='small fa'
{ active: config.lineWidth === pen.lineWidth } //active 也是类名
]"
//行内 js都可用 {{ row.usersex == 1 ? "男" : row.usersex == 2 ? "女" : "未知" }}
关于v-if 的知识点,在弹窗情况下,每次都会重新渲染数据,解决滚动条在底部的话,再次打开弹窗数据重新渲染(会回到顶部)
给数组添加属性(变为响应式数据)
//set 方法 第一个参数原数据 、第二个参数属性名、 第三个参数为值
this.$set(obj, "s_m", parseInt(theTime1));
删除属性(加$会视图更新)
this.$delete(this.testData,"name")
[map详解](https://www.cnblogs.com/-constructor/p/12592200.html)
直接调用子组件的方法并传值
//优点就是可以直接子组件里的init方法并且传值
//缺点就是子组件一直在运行 不能控制复用(还是用v-if哈哈)
this.$refs.add_or_update.init(this.form_bank);
vue 播放器https://www.npmjs.com/package/vue-aliplayer-v2
ue里面本身带有两个回调函数
一个是`Vue.nextTick(callback)`,当数据发生变化,更新后执行回调。
另一个是`Vue.$nextTick(callback)`,当dom发生变化,更新后执行的回调。
v-for 可以循环数字
解决浏览器缓存
//配置 打包文件后缀加时间戳 根目录的vue.config.js文件 //打包时css和js文件名都加上时间戳 const timestamp = new Date().getTime(); const webpack = require("webpack"); module.exports = { lintOnSave: false, productionSourceMap: process.env.NODE_ENV !== "production", //打包不生成map文件 devServer: { open: true }, css: { extract: { filename: `css/[name].${timestamp}.css?t=${timestamp}`, chunkFilename: `css/[name].${timestamp}.css?t=${timestamp}` }, loaderOptions: { less: { lessOptions: { javascriptEnabled: true } } } }, configureWebpack: { plugins: [ new webpack.ProvidePlugin({ "window.Quill": "quill/dist/quill.js", Quill: "quill/dist/quill.js" }) ], output: { filename: `js/[name].${timestamp}.js?t=${timestamp}`, chunkFilename: `js/[name].${timestamp}.js?t=${timestamp}` }, externals: { BMap: "BMap" } } }; 二、在index.vue文件、HTML标签设置HTTP头信息 <meta http-equiv="pragram" content="no-cache"> <meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate"> <meta http-equiv="expires" content="0"> 备注:HTTP头信息“Expires”和“Cache-Control”为应用程序服务器提供了一个控制浏览器和代理服务器上缓存的机制。HTTP头信息Expires告诉代理服务器它的缓存页面何时将过期。HTTP1.1规范中新定义的头信息Cache-Control可以通知浏览器不缓存任何页面。当点击后退按钮时,浏览器重新访问服务器已获取页面。如下是使用Cache-Control的基本方法: 1) no-cache:强制缓存从服务器上获取新的页面 2) no-store: 在任何环境下缓存不保存任何页面 HTTP1.0规范中的Pragma:no-cache等同于HTTP1.1规范中的Cache-Control:no-cache,同样可以包含在头信息中。
vue 下载
//一、下载单文件 //直接a标签跳转下载 <a :href="$api.showImageUrl + item.resourceurl" :download="item.resourcename" id="down" style="margin-right: 10px" > <Icon type="ivu-icon ivu-icon- iconfont icon-xiazai" style="margin-right: 5px" />下载 </a> //创建节点下载 父元素需要添加 id="down" //资源分类1音频2视频3图片4文档 let url = this.$api.downLoadUrl + this.info_details.resourceurl; let surl = this.info_details.resourceurl; let filename = surl.substring(surl.lastIndexOf("/") + 1, surl.length); const a = document.createElement("a"); // 创建a标签 document.getElementById("down").appendChild(a); a.setAttribute("download", filename); // download属性 a.setAttribute("href", url); // href链接 a.click(); // 自执行点击事件 document.getElementById("down").removeChild(a); //二、下载多文件 for (let i = 0; i < data.resources.length; i++) { const iframe = document.createElement("iframe"); iframe.style.display = "none"; iframe.src = this.$api.downLoadUrl + data.resources[i].resourceurl; document.body.appendChild(iframe); //这里删除节点和网络任务没关系 setTimeout(() => { iframe.remove(); }, 2 * 60 * 1000); } //三、下载应用 let url = this.$api.baseImageUrl + res.obj.versionpath; let newFileUrl = encodeURI(url, "utf-8"); window.location.href = newFileUrl;