工作中遇到的问题及小知识点
一、本地vue项目配置IP地址访问,可以让同局域网内的同事预览
解决:在package.json文件中 dev中配置 --host 本机IP
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 10.10.50.73",
"start": "npm run dev",
"build": "node build/build.js"
},
二、Vue使用axios请求数据,默认post请求传参是json格式,但后台需要formData格式
1、 FormData格式
2、qs解决
解决:使用node的qs模块 qs是一个npm仓库所管理的包,可通过npm install qs
命令进行安装.
qs.parse()将URL解析成对象的形式
let url = 'method=query_sql_dataset_data&projectId=85&appToken=7d22e38e-5717-11e7-907b-a6006ad3dba0'; qs.parse(url); // { // method:'query_sql_dataset_data', // projectId:85, // appToken:'7d22e38e-5717-11e7-907b-a6006ad3dba0' // }
qs.stringify()将对象 序列化成URL的形式,以&进行拼接
let obj= { method: "query_sql_dataset_data", projectId: "85", appToken: "7d22e38e-5717-11e7-907b-a6006ad3dba0", datasetId: " 12564701" }; qs.stringify(obj); //'method=query_sql_dataset_data&projectId=85&appToken=7d22e38e-5717-11e7-907b-a6006ad3dba0'
import axios from 'axios';
import qs from 'qs';
this.$axios({
method: 'post',
url: url,
data: qs.stringify(data)
}).then(res => {})
三、过滤器(简单)
filters: {
visitedFilters(value) {
let set = {0: "未到访", 1: "已到访"};
return set.hasOwnProperty(value) ? set[value] : value
},
},
四、在H5中使用qrcodejs2生成二维码
npm i qrcodejs2
import QRCode from 'qrcodejs2'
this.$nextTick(() => {
document.getElementById('qrcode').innerHTML = '';
this.qrCode = new QRCode('qrcode', {
width: 200, // 设置宽度,单位像素
height: 200, // 设置高度,单位像素
text: this.urlData.urlValue // 设置二维码内容或跳转地址
});
})
五、深拷贝,浅拷贝问题
在做el-select 下拉数据过多时,region_code ,region_name 以分页形式显示(显示前15条,之后可进行搜索),但是在数据回显时,发现在15条数据之后,因为没有数据,回显失败,
进行数据回显时(region_code和region_name互换值),在不进行更改时,保存提交时时(region_code和region_name再转换回来)时发现
问题:
当用obj1复制了一个对象obj2, 更改obj1内的属性时,obj2内的会同步更改,
原因:
因为 = 复制为浅拷贝,只拷贝了它的栈内存中的"引用路径",所以当更改obj1时,更改了堆内存中的值,obj2的指向也是它,所以会同步修改
解决:
运用深拷贝,复制时不仅要拷贝栈内存中的引用路径,堆内存中的值也要同步复制
方法1:
首推的方法简单有效,JSON.stringfy()和JSON.parse()即可搞定。但是这种简单粗暴的方法有其局限性。当值为undefined、function、symbol 会在转换过程中被忽略。。。所以,对象值有这三种的话用这种方法会导致属性丢失。
var person = {
name :'tino',
say: function(){
console.log('hi');
},
ok: syb,
un: undefined
}
var copy = JSON.parse(JSON.stringify(person))
方法2:
写个函数递归复制
function deepCopy(obj) {
var result = Array.isArray(obj) ? [] : {}; //Array.isArray(object) 检测是否为数组 传进来的object是数组,返回true,如果不是数组,则返回false
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object' && obj[key]!==null) {
result[key] = deepCopy(obj[key]); //递归复制
} else {
result[key] = obj[key];
}
}
}
return result;
}
六、https使用iframe嵌入http资源的问题(了解,未使用)
目前现象:
https 网站 使用iframe嵌入http资源网站的内容,会弹出“是否加载不安全的内容”的提示,点击“加载”按钮后显示正常。
对用户来说显示不友好。
问题原因:
https中使用http的资源时,浏览器会认为可能会不安全, 会自动弹出“是否加载不安全的内容”的提示。
该提示由浏览器自动弹出,不能通过修改代码的方式解决。
https中使用https资源时,如果https资源不安全,同样会报错。
尝试解决方案:
1) 使用自定义ssl证书,将http资源模拟成为https
使用nginx或者apache服务器,将http协议的资源包装为https协议的资源使用,前提条件是nginx或者apache服务器可以同时访问到http的资源和https的资源,将http链接地址从原网站改为nginx或apache包装的https的地址即可。
否则会报错“ 因为没有使用有效的安全证书进行签名,该内容已被屏蔽”的新错误提示。
2)使用第三方签名的ssl证书,将http资源转换成为https
和方案1相同,但是使用第三方签名CA证书,网站可以正常访问。
但是第三方的CA签名的ssl证书是需要按年付费的, 价格 从每年几百到每年几千元均有。
3) 要求http网站资源提供https的格式内容,且使用的ssl证书为第三方CA签名证书。
七、当在 element ui 使用 resetFields()重置表单后,表单无法输入的问题
this.$refs[formName].resetFields(); 使用后部分表单无法输入
解决:
resetFields 是对整个表单进行重置,讲所有字段值重置为"初始值",并移除校验结果.
所以给表单默认一个初始值就可以解决
八、vue中子组件的created、mounted钩子中获取不到props中的值问题
当props中接受的值是动态获取的,这种情况下,钩子中是取不到值的,或者取到的一直是默认值。
原因:
出现这种情况的原因, 因为父组件中的要就要传递的 props 属性 是通过 发生ajax请求回来的,
请求的这个过程是需要时间的,但是“子组件的渲染要快于ajax请求过程”,所以此时 created 、 mounted 这样的只会执行一次的生命周期钩子,已经执行了,但是 props 还没有流进来(子组件),所以只能拿到默认值。
解决:
使用watch处理,监听 传入的值,当它由空转变时就会触发,这时候就能取到了,created、mounted,中依旧拿不到值,拿到值后要做的处理方法也需要在 watch 里面执行。
九、在vue的dialog中嵌套dialog,弹出里层的dialog时,发现被dialog的遮罩层挡住了
解决:
对于确实需要嵌套 Dialog 的场景,提供了append-to-body属性。将内层 Dialog 的该属性设置为 true,它就会插入至 body 元素上,从而保证内外层 Dialog 和遮罩层级关系的正确。
十、对接七陌外呼系统
引入插件:
import md5 from 'js-md5'; //md5加密
let Base64 = require("js-base64").Base64; //转化base64 https://www.javascriptcn.com/read-41473.html
import moment from "moment"; //用于获取时间戳 http://momentjs.cn/docs/
//外呼接入函数(依据七陌接口文档 https://developer.7moor.com/v2docs/dialout/)
callOut(val) { const exten = "8003"; //坐席工号 const ACCOUNTID = "N00000037833"; //账户编号(ACCOUNTID) const APISecret = "1e86bcb0-fbc0-11e9-833b-1f632fa2b92c"; //帐号APISecret const timestamp = moment().format("YYYYMMDDHHmmss");//获取当前时间的时间戳 const sig = md5(`${ACCOUNTID}${APISecret}${timestamp}`).toUpperCase(); //url参数sig的值为 32位大写MD5加密 (帐号Id + 帐号APISecret +时间戳) const auth = Base64.encode(`${ACCOUNTID}:${timestamp}`); //Authorization是包头验证信息 Authorization的值为 Base64编码(账户Id +冒号+时间戳) this.$axios({ method: 'POST', url: `/7moor/v20160818/call/dialout/${ACCOUNTID}?sig=` + sig, data: { FromExten: exten, //坐席工号 Exten: val.customer_mobile, //外呼的电话号码 ExtenType: "sip" //座机方式 }, headers: { "Content-Type": "application/json;charset=utf-8", 'Authorization': auth } }).then((res) => { console.log(res) }) },
跨域问题详解: https://www.jianshu.com/p/a0dd1e712c3a
请求会出现跨域的问题:config/index.js 配置本地跨域代理,上线时需要配置nginx代理
proxyTable: { '/7moor': { target: 'https://apis.7moor.com', changeOrigin: true, pathRewrite: { '^/7moor': '/' //实际请求去掉 /7moor 以 / 代替 } } },
配置表
dev: { // 静态资源文件夹 assetsSubDirectory: 'static', // 发布路径 assetsPublicPath: '/', // 代理配置表,在这里可以配置特定的请求代理到对应的API接口 // 例如将'localhost:8080/api/xxx'代理到'www.example.com/api/xxx' // 使用方法:https://vuejs-templates.github.io/webpack/proxy.html proxyTable: { '/api/cms': { target: 'http://localhost:31001', pathRewrite: { '^/api': ' ' //实际请求去掉/api以空字符串代替 } } },
十一、用postcss-px2rem插件,样式中px强制不自动转换为rem的方法
#box { height: 44px width: 100% font-size: 24px;/*no*/ //如果不想用插件转换可以用/*no*/标识符 }
问题:当打包编译过 之后 /*no*/这个标签会被当成注释给去掉,
解决:把px改成PX大写,浏览器一样识别,px2rem不会转换它。
十二、vue中在data中引入图片的路径方法
---错误的引入方式: export default { data () { return{ imgUrl_homePage:'@/assets/img/homePage_active.png' } } } ---import在外部引入 import img_url from '@/assets/img/homePage_active.png' export default { data () { return{ imgUrl_homePage:img_url } } } ---require内部引入 export default { data () { return{ imgUrl_homePage:require('@/assets/img/homePage_active.png') } } }
十三、使用vant中van-list插件时为什么 List 初始化后会立即触发 load 事件?
List 初始化后会触发一次 load 事件,用于加载第一屏的数据,这个特性可以通过immediate-check属性关闭。
loading 的设置也会影响到load事件的触发
十四、依据一个对象属性的值,判断这个数组是否含有这个对象,有的话删除,没有的话增加
const ind = this.chooseSelectedPrice.findIndex( item => item.value === priceWen ); if (ind !== -1) { this.chooseSelectedPrice.splice(ind, 1); } else { if (this.qieNum2 === 0) { this.chooseSelectedPrice.push({ value: priceWen, start: item.start, end: item.end, type: 0 }); } else { this.chooseSelectedPrice.push({ value: priceWen, start: item.start, end: item.end, type: 1 }); } }
十五、数组的切割中arr.splice(n,1)
使用时不可let arr2 = arr.splice(n,1) 因为它是改变原数组的,不会有返回值
十六、localStorage本地存储时,key值不能为变量,可以通过以下方法变通
obj[phone] = JSON.stringify(celPhone); this.$tool.setStorage(obj);//集成的方法 delete celPhone[buildingId];
十七、关键字搜索高亮
pushHTML(text, str) { let arr = str.split(text); let newText = arr.join('<span style="color:#00A4FF">' + text + "</span>"); return newText; },
十八、router-link 绑定事件不生效
加 .native 修饰符就可以执行事件了。
<router-link to="/date" @click.native="nav_click">最新</router-link>
原因:
1: 因为它是自定义标签,根本就没有事件和方法,所以不触发,加个native 就是告诉vue 这个标签现在有主了 它是H5标签 可以加事件了。
2:父组件要想在子组件监听自己的click事件就得加native,router-link是标签啊。哪里有父组件????
router-link 其实就是一个封装好的 .vue 组件,所以需要 加.native修饰符才能绑定事件
十九、vue跳转当面页面(页面路径不变化,携带参数改变)页面不刷新问题
解决1、router-view 中加一个 key
<router-view :key="$route.fullPath" />
解决2、路由改变时刷新当前页
this.$router.go(0);
vue 框架this.$router.go(0) safari 浏览器不刷新
用原生 window.location.reload()
二十、(粗心)当用组件,时,用到v-model,或者动态绑定的值,无效时,要看清当前组件需要绑定的值得类型,好多次,number类型的绑定成了string,死活不出效果,调试很久,谨记。
字符串定义 未赋值时不能使用,否则会报undefined
二十一、本地存储封装
/* 获取浏览器存储里key为item的值 @param item 要获取的数据的索引值 Usage: helper.get('token') */ function getStorage(item) { var value; value = window.localStorage.getItem(item) return (value ? decrypt(value) : '') } /* 将数据存储在浏览器存储里 @param obj 要存储的数据对象 Usage: j.set({ token: 'as23q1sdf212swsxx', uname: 'jacket' }) */ function setStorage(obj) { for (var key in obj) { if (obj.hasOwnProperty(key)) { window.localStorage.setItem(key, encrypt(String(obj[key]))); } } }
二十二、jquery获取参数
detail.html?order_id=10 <Script language="javascript"> function GetRequest() { var url = location.search; //获取url中"?"符后的字串 var theRequest = new Object(); if (url.indexOf("?") != -1) { var str = url.substr(1); strs = str.split("&"); for(var i = 0; i < strs.length; i ++) { theRequest[strs[i].split("=")[0]]=unescape(strs[i].split("=")[1]); } } return theRequest; } </script> detail.html?order_id=10&uid=3 function GetRequest() { var url = location.search; //获取url中"?"符后的字串 var theRequest = new Object(); if (url.indexOf("?") != -1) { var str = url.substr(1); strs = str.split("&"); console.log(strs) for (var i = 0; i < strs.length; i++) { theRequest[strs[i].split("=")[0]] = decodeURIComponent(strs[i].split("=")[1]); } } return theRequest; }
二十三、jquery给元素增加一个父元素
let d = $("table").clone(); //clone(includeEvents) 方法生成被选元素的副本,包含子节点、文本和属性。 includeEvents 可选。布尔值。规定是否复制元素的所有事件处理。 默认地,副本中不包含事件处理器。 let f = $("table").parent(); console.log(d,f) $("table").remove(); $(f).append("<div class='kg'><div>"); $(".kg").html(d)
以上为沙雕做法而且有bug
$('table').wrap("<div class='kg'></div>");一句搞定它不香么
二十四、整行字体渐变色
//默认值。替换内容拉伸填满整个content box, 不保证保持原有的比例。 object-fit: fill; //保持原有尺寸比例。保证替换内容尺寸一定可以在容器里面放得下。因此,此参数可能会在容器内留下空白。 object-fit: contain; //保持原有尺寸比例。保证替换内容尺寸一定大于容器尺寸,宽度和高度至少有一个和容器一致。 //因此,此参数可能会让替换内容(如图片)部分区域不可见 object-fit: cover; //保持原有尺寸比例。同时保持替换内容原始尺寸大小。 object-fit: none; //最终呈现的是尺寸比较小的那个,类似于依次设置none或contain。 object-fit: scale-down;
htmljs锚点滚动
function scrollDom() { allHeights = []; $(".activity_main_li").each((index, item) => { let top = '', s = $("." + $(item).attr("currentname")); allHeights.push(s.offset().top) }) $(window).scroll(function() { scrollTopDom() }) }; function scrollTopDom() { // 获取当前滚动的高度 var top = document.body.scrollTop + document.documentElement.scrollTop; top = top + 90; if (review) { review = false; scrollHeight = document.body.scrollHeight; } let index = 0; if (top >= allHeights[allHeights.length - 1]) { index = allHeights.length - 1 } else { $(allHeights).each((i, res) => { if (top < res && top > allHeights[i - 1]) return index = i - 1 }) } if (currentPoint != index && !currentGun) { currentPoint = index; $(".activity_main_li").removeClass("active"); $($(".activity_main_li")[index]).addClass("active") scrollX(index) } // 滚动条距离顶部的距离 大于 200px时 if (top >= 500 && flag) { flag = false; $(".activity_main_title").css({ "position": "fixed", "top": "0", "z-index": "9", "background-color": "#0E0E0E" }); } else if (top < 500) { flag = true; $(".activity_main_title").css({ position: 'relative', backgroundColor: 'transparent' }); } }
&&&&&&&&&&&&&&&&&&&《项目中的知识点》&&&&&&&&&&&&&&&&&&&&&&&&
1、hasOwnProperty:
hasOwnProperty()方法返回一个布尔值,判断对象是否包含特定的自身(非继承)属性。
function Person(name, age) {
this.name = 'Tom';
this.age = 11;
};
Person.prototype = {
job:'资深前端开发工程师',
};
console.log(Person.hasOwnProperty('name'))//true
console.log(Person.hasOwnProperty('job'))//false
2、JSON.stringify()
JSON 通常用于与服务端交换数据。
在向服务器发送数据时一般是字符串。
我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符串。
JSON.parse()
JSON 通常用于与服务端交换数据。
在接收服务器数据时一般是字符串。
我们可以使用 JSON.parse() 方法将数据转换为 JavaScript 对象。
3、localStorage
localStorage 可以在浏览器中存储键值对的数据,能长期储存
localStorage中的键值对总是以字符串的形式存储,并且只能访问当前域名下的数据,不能跨域名访问
可以通过setItem方法增加了一个键值对数据,如果该键已存在,那么该键对应的值将被覆盖
localStorage.setItem("name","xiaozhong")
可以用getItem方法读取对应键的值数据
localStorage.getItem("name")
可以用removeItem方法移除对应键
localStorage.removeItem("name")
可以用clear方法移除当前域名下所有的键值对数据
localStorage.clear()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构