感谢!!!
中途文章被覆盖了!!!
感谢大佬!!救命帖!!
!!!!!!!!!!!
git相关
git拉取报错
拉取时报错 The project you were looking for could not be found.
1.首先确认vpn连接正常
2.前往控制面板-用户账户-凭据管理器
或控制面板-所有控制面板选项-凭据管理器
在"Windows凭据"下找到git地址,更新git账号。(尝试有效!)
3.还是报错可以尝试通过以下命令卸载重装git credentials manager
$ git credential-manager uninstall
卸载
$ git credential-manager install
安装
参考博客
git报错 Cannot do a soft resset in the middle of a merge
git reset --merge
取消合并 (亲测有效)
or
git rebase
将当前分支重新设置基线
git提交修改的时候报错: 无法推送refs到远端
运行命令
git pull origin yourBranch -f
git有冲突,解决冲突
1.提交代码时有冲突会把有冲突的版本的更改全拉下来,不要慌
2.在源代码管理会有显示冲突的文件,点开文件可以看到冲突的两版本内容
3.可以选择"now…“(当前版本)或”"(上一版本)解决冲突
4.解决后保存,在源代码管理中暂存解决完冲突的文件
5.最后将所有的更改提交,推送就ok了(完美)
vue相关
引用自定义组件,多次使用组件间会相互影响
同一组件在页面中使用多次,对其中一个进行操作后会对其他组件有影响而产生报错
1、使用组件时绑定了同一变量,试试区分两个组件绑定值
2、引用时只创建里一个组件实例,试试区分两个实例
参考博客
IOS页面会上下弹性滚动
再IOS中一个页面存在一个滑动框,滑动滑动框里内容,会偶尔将整个页面滑动,类似bounce回弹
使用代码([参考博客] (https://blog.youkuaiyun.com/a460550542/article/details/90598711)) --亲测不可用!只会禁止整个页面的滚动
document.body.addEventListener('touchmove', function (e) {
e.preventDefault(); //阻止默认的处理方式(阻止下拉滑动的效果)
}, {passive: false}); //passive 参数不能省略,用来兼容ios和android
亲测可用,只需要再整个页面加个样式
height: 100%; width: 100%; position: fixed; top: 0; left: 0;
复制文本到剪切板
//复制文本
copyText(text) {
// 直接构建input
const _input = document.createElement("input");
// 设置内容
// _input.value = text;
_input.setAttribute("value", text);
// 添加临时实例
document.body.appendChild(_input);
// 选择实例内容
_input.select();
// 执行复制
document.execCommand("Copy");
// 删除临时实例
document.body.removeChild(_input);
},
但是还会有个问题… 如果文本是需要发接口查询返回,查完接口success里调用复制方法,会导致复制失败
目前的解决办法: 更换发接口时间,避免发完接口直接复制(还没有完美解决办法)
使用emoji
带有emoji的文本想要保存到后端,但是因为编码问题导致直接传到后台会乱码$*d@&1K(瞎写的)
可以传后端之前将带有emoji的文本编码成字符串
从后端取到后再解码成带有emoji的文本
//emoji编码
emojiEncode(e) {
var n = /[\ud800-\udbff][\udc00-\udfff]/g;
return e = e.replace(n, function (e) {
var n, r;
return 2 === e.length ? (n = e.charCodeAt(0), r = e.charCodeAt(1), "&#" + (1024 * (n - 55296) + 65536 + r - 56320) + ";") : e
})
},
//emoji解码
emojiDecode(e) {
var n = /\&#.*?;/g;
return e.replace(n, function (e) {
var n, r, t;
return 9 == e.length ? (t = parseInt(e.match(/[0-9]+/g)), n = Math.floor((t - 65536) / 1024) + 55296, r = (t - 65536) % 1024 + 56320, unescape("%u" + n.toString(16) + "%u" + r.toString(16))) : e
})
}
在页面显示网络链接图片
需要显示链接图片,例如https://i0.hdslb.com/bfs/archive/ca375eb31fa90b8e23b88ed3433c2f60de1c2e6e.png
需要再img标签里添加一个属性
<!--let url = "https://i0.hdslb.com/bfs/archive/ca375eb31fa90b8e23b88ed3433c2f60de1c2e6e.png";-->
<img
class="img"
:src="url"
referrerpolicy="no-referrer"
/>
在页面显示base64图片
需要显示base64图片,例如 (base64太长了)
需要在标签里的src属性拼接一下
<!--let url = "bolabolabola(base64)";-->
<img
class="img"
:src="'data:image/png;base64,' + url"
/>
input想要只输入数字
<input type="number" :maxlength="20"/>
这样安卓没有问题,ios还是能输入其他
<input type="number" pattern="[0-9]*" :maxlength="20"/>
这样ios会弹出是有数字的键盘
input类型为number限制字数
<input type="number" :maxlength="20"/>
字数没有限制,number换成其他就可以
在输入回调里控制 (这里是组件的回调)
@on-change="
() => {
if (idNo.length > 20) idNo = idNo.slice(0, 20);
}
"
实现播放mp3
实现播放MP3文件
参考博客
<template>
<x-view id="P180301">
<!--触发播放音频按钮-->
<x-view @click.native="playAudio">Play</x-view>
<audio id="audioPlayer" autoplay="autoplay">
<!--音频资源-->
<source
id="tts_source_id"
src="../../../assets/beinvited.mp3"
type="audio/mpeg"
/>
</audio>
</x-view>
</template>
<script>
export default Page({
playAudio() {
var ttsAudio = document.getElementById('audioPlayer');
ttsAudio.play(); //播放音频
},
})
</script>
样式还没有实现(凑合)
运行程序时报错'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序
切换分支后运行程序报错了↓
原因还不太清楚,突然就不行了(难道突然版本就不对了??)
解决方法:重新下载安装最新的 webpack-dev-server
命令:npm install webpack-dev-server --save-dev
地图&搜索
这里使用的sdk已被弃用,无法限制搜索类型,最新需要使用WebService
需求:进入页面显示当前定位,搜索展示位置列表
参考文档:腾讯位置服务
<!--xMap组件-->
<template>
<div :id="id">
<slot></slot>
<div class="x-map-relocate" v-if="local" @click="onLocalClick">
<img
width="25"
height="25"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAYFBMVEUAAABRUVFRUVFSUlJRUVFRUVFRUVFRUVFSUlJSUlJSUlJSUlJSUlJRUVFSUlJSUlJSUlJTU1NSUlJSUlJSUlJOTk5SUlJSUlJSUlJRUVFTU1NSUlJSUlJRUVFSUlJSUlJ5TLkYAAAAH3RSTlMAqhzjh/K7FUTa7T1f1Z2PVCWwLGgNfnY3owjLyL5OoP/65AAAA9RJREFUeNrtm9ly6yAMQAXYxmscr82u///Le6fTQnaEgZJ2cp4TIYOEJBDw5o0TnKVp30E0eIn/KTnEguEnDGKR4icpxAK/ACJvBf6SAlNVz6sMv8hWc11N8FMM46rBOzSrcYDgDHODTxBtDgHhiUAjIuEQhrxHIn2Iacj3aEGzBr9sjmjJoQJ/yC0ugEnwRF3iDQVLxhy/yMeE3THPsvZj+tnN4O1a3u6Ect0WeEUmwZm8vDKveXi8FQ/JlQ7C2RLGq086mWJBxfCCGVzYXUpbcUow6lZ4DnMJOdmFpI4aDbsLvY8TLEQeUFPkNuG4alCzlwvHPxeS7OzygV2CmmaRBtMeFWLzLCkt4R4bcTYH0wL7y8zu3D81M3kuYbcg51ck8IDOUJi0Dr7wgYqP56UZ43QpdHJU1OBAjYoKLJCCMj5dA+sSMqPPHH0tsyVqJ+BMaz+ZsqQobT+dpbT1QEH6B92gtkCiwm824IWNpcCjNgBPJCowWm0BxQ48sVNhLQcze/udg76qB4sJYOARRp8CVX8N4JGO/Flc5X/gFZUncqrBcvBKR3Ut8V3gglf00gqiuebgF23cG9IKNOCdgrQGhUM9Q7SuAp4wOPogSXZnrAS1lkHWYCR4awsBaAk7zHfQWEMA1mYDn/ALSRTJijQtmFKXuMlOxl2goA0vVOCmqSCMYbbWEYO+pPTcpTcmp7MWRx/f/i+z0QlGskVpTvTjnpUxgc7JTq0R9HCQ3S0y8Q5p39EmQLvuMtm8xAeU3Fi8G5J+kmyGD2GkFbjvu3TZKT4khbukDr9UpJQflQEV0LJ7H0vQwDl2sjv/RkiSbXYVxsO5IeOvtBG9ylZsE4wSx2DkHo6TAOG4UutJ4aTsoDg5JCROKdm2SdNma52SvW5SGj8tH5UReEebQP3KpZm5hHUvThuXEjZ8eb4JdkBxUgcUkY5oMqJ9JwZTcT6kmiMd023V6VuUg0rtgyzSUW2vjDvKYbX+qkOk4/pCTUCUCwtdymdRrmzsBW6DXVr9lmu7s4vL1uvF5e+5ug1yeS2kveG6azCiogrVwNB3RCmWMDRbIg/QwqExNLGYe8vl8UxC0Dae9L4ZCVQcpt/YyAQg96gpKhsF8gI1B+mnmS0bqAoM7OJ/k792vm5BO9/2hxsac62z+16ujVlTJOFaOg09aQrRrvmtAnzdCnJTq3tbr+gv23p7Q1tvjMbmrQR/bLJIrd2a6mg1fJD+eoZEmGH4wA8cZg4Ggj7xqCA4Xf3okUvdgYG/8cznJR46vRV4EQVUb3ks+thPPru4j151b/mbNy78A1GCgngNVC3TAAAAAElFTkSuQmCC"
/>
</div>
</div>
</template>
<script>
export default {
name: 'x-map',
data() {
return {};
},
// 接收外部请求
props: {
// id
id: {},
// 经度
longitude: {
default: 116.39747,
},
// 纬度
latitude: {
default: 39.908823,
},
// 缩放级别
scale: {
default: 16,
},
// 标记点
markers: {},
// 路线
polyline: {},
// 多边形
polygons: {},
// 圆
circles: {},
// 缩放视野以包含所有给定的坐标点
'include-points': {},
// 显示带有方向的当前定位点
'show-location': {},
// 是否支持缩放
'enable-zoom': {
default: true,
},
// 是否支持拖动
'enable-scroll': {
default: true,
},
local: {
default: true,
},
},
// 监听器
watch: {
latitude(value) {
//
this.myLatlng = new qq.maps.LatLng(this.latitude, this.longitude);
//
this.mapObj.setCenter(this.myLatlng);
//
this.initMaks(this.myLatlng);
},
longitude(value) {
//
this.myLatlng = new qq.maps.LatLng(this.latitude, this.longitude);
//
this.mapObj.setCenter(this.myLatlng);
//
this.initMaks(this.myLatlng);
},
enableScroll(value) {
// 设置选项
let myOptions = {
zoom: this.scale,
center: this.myLatlng,
// 街道地图
mapTypeId: qq.maps.MapTypeId.ROADMAP,
// 缩放控件
zoomControl: false,
// 拖动
draggable: value,
// 地图类型控件
mapTypeControl: false,
};
// 地图对象
this.mapObj.setOptions(myOptions);
},
},
//
methods: {
onLocalClick() {
//
this.$emit('bindlocal');
},
// 返回地图对象
getMap() {
return this.mapObj;
},
//
initMaks(myLatlng) {
// 标记
this.marker && this.marker.setMap(null);
//
this.marker = new qq.maps.Marker({
position: myLatlng,
animation: qq.maps.MarkerAnimation.DROP,
map: this.mapObj,
});
//
if (this.geocoder) {
this.geocoder.getAddress(this.myLatlng);
this.geocoder.setComplete((result) => {
//
this.geoInfo = result;
this.$emit('bindmaks', result);
});
}
},
// 显示地图
initMap() {
//
if (!window.qq) {
$Fw.Logger.debug('加载地图组件失败!');
return;
}
// 地址解析
this.geocoder = new qq.maps.Geocoder();
// 经纬度
this.myLatlng = new qq.maps.LatLng(this.latitude, this.longitude);
// 设置选项
let myOptions = {
zoom: this.scale,
center: this.myLatlng,
// 街道地图
mapTypeId: qq.maps.MapTypeId.ROADMAP,
// 缩放控件
zoomControl: false,
// 拖动
draggable: this.enableScroll,
// 地图类型控件
mapTypeControl: false,
};
// 地图对象
this.mapObj = new qq.maps.Map(
document.getElementById(this.id),
myOptions
);
// 标记
this.initMaks(this.myLatlng);
//添加监听事件
window.qq.maps.event.addListener(this.mapObj, 'click', (event) => {
console.log(11);
//
event.geoInfo = this.geoInfo || {};
//
this.$emit('bindtap', event);
});
},
},
mounted() {
// 移除腾讯地图logo
this.$el.addEventListener('DOMNodeInserted', (e) => {
let del = e.target.innerHTML;
if (del.includes('到腾讯地图查看此区域') || del.includes('map.qq.com')) {
e.target.remove();
}
});
// 初始化地图
this.initMap();
},
//
// beforeDestroy(){
// window.qq.maps.event.removeListener(this.mapObj);
// this.$el && this.$el.removeListener('DOMNodeInserted')
// }
};
</script>
<style lang="less">
/* .x-map-relocate {
position: absolute;
width: 25px;
height: 25px;
bottom: 10px;
left: 15px;
z-index: 1;
} */
</style>
又包装了一个可以搜索的地图组件
组件里mounted不执行
写组件时mounted不执行 created执行
因为代码里本来就写了一个mounted = =
0
和false
和''
代码里遇到的,了解并记录一下
0 == false; //true
原理: 布尔值作比较的时候,会先把布尔转为数值,即true→1 false→0
'' == false; //true
原理: 字符串比较的时候会转为布尔类型,即空字符''→false 其他→true
0 == ''; //true
原理: 同上
接着
'0' == false; //true
原理: 字符串和数值类型比较的时候string会转化成number
'0' == ''; //false
原理: 字符串和字符串比较,不转类型
!!'0'; //true
原理: 懂?
比较灵异事件
两个值做等于比较,打印出来为"BB1092323","BB1092323",false
完全一模一样,但结果是false
第二个字符串开头有个空格!!
ios搜索组件弹出的键盘右下角按键名为“换行”
搜索组件中input中type为search,安卓弹出键盘有“搜索”按键,苹果键盘仍为“换行”
可以在组件内部或组件调用处,外部套一层
<form action="javascript:return true"></form>
有的说<form action=""></form>
也行,实测后发现不可用,这样点击“搜索”后会跳转页面
ios中input输入过长文字不可滑动
在input中输入过长文字会隐藏并可滑动查看,安卓如此
但ios中隐藏不可滑动,只可以长按选中文字形式滑动内容
暂无解决办法
数字格式修改
根据需求,数字展示万以上以万为单位,亿以上以亿为单位,整数不补0
// 数据格式处理
// 超过万单位用万,超过亿单位用亿,整数不补0
// defValue--默认值,无value时显示
export function numberDataFormat(value, defValue) {
if (!value) return defValue;
let reValue = value < 0 ? -Number(value) : Number(value); //修改为整数值
if (reValue >= 100000000) { // 亿
reValue = Number(parseFloat((Number(value) / 100000000).toFixed(2))).toLocaleString() + '亿';
} else if (reValue >= 10000) { // 万
reValue = Number(parseFloat((Number(value) / 10000).toFixed(2))).toLocaleString() + '万';
} else {
reValue = Number(parseFloat(Number(value).toFixed(2))).toLocaleString();
}
return reValue;
}
数据加密解密
跳转三方链接页面,需要传送敏感字段,需要加密
参考文档
有两种加密引用包,crypto-js和JSEncrypt
可根据所需的不同加密形式进行选择
需要提供秘钥,放到配置中(一般后端提供)
// 使用AES加密
import CryptoJs from 'crypto-js'
getJSEncrypt(cfg, keyString){
const key = CryptoJs.enc.Utf8.parse(keyString);
const word = CryptoJs.enc.Utf8.parse(cfg);
const encrypted = CryptoJs.AES.encrypt(word, key, {mode: CryptoJs.mode.ECB, padding: CryptoJs.pad.Pkcs7});
return encrypted.toString();
},
获取本地文件
获取本地文件并上传到OSS
还没做完,写下大概思路吧
选择文件使用<input type="file"/>
加载文件使用FileReader
tips:
数据格式和网上说的不太一样,需要在浏览器查看数据
手机上会有因权限不允许导致触发error
手动触发onerror方法:在读取前debugger住,再修改文件名称,再继续运行
FileReader文档
<!--accept:限制选择类型 multiple:允许多选-->
<input
@change="onChangeFile"
type="file"
accept="*"
multiple
id="fileInput"
/>
<!--加载状态-->
<x-view>{{ readyStateMap[readyState] }}</x-view>
readyState = 0;
readyStateMap = ["未开始加载", "加载中", "加载结束", "加载失败", "加载成功"];
onChangeFile(e) {
console.log("===========onChangeFile", e, e.target.files[0])
let files = e.target.files;
let that = this;
if (!files || !files.length) return false;
const fileReader = new FileReader();
that.readyState = fileReader.readyState;
console.log("========create fileReader", fileReader, fileReader.readyState);
fileReader.onloadstart = (p) => {
console.log("========loadstart", p, fileReader.readyState);
that.readyState = fileReader.readyState;
}
fileReader.onloadend = (p) => {
console.log("========loadend", p, fileReader.readyState);
}
fileReader.onload = () => {
console.log("========onload", fileReader.result);
that.readyState = '4';
}
fileReader.onerror = (err) => {
console.log("========onerror", err.target.error.message, err.target.error.code, fileReader.readyState);
that.readyState = '3';
}
// 1表示未找到文件,2表示安全性错误,3表示读取中断,4表示文件不可读,5表示编码错误。
fileReader.readAsText(files[0]);
},
CSS相关
换行
word-wrap: break-word;
absolute垂直居中
top: 50%;
margin-top: -10px; //10px为高度的一半
图片显示不变形
需要显示图片在正方形容器里,且不改变原比例
比如: 图片是这样滴
直接展示:
.pic {
height: 60px;
width: 60px;
margin: 10px 17px 13px 0;
}
改为根据最大边保持原比例,保留左下角
.pic {
height: 60px;
width: 60px;
margin: 10px 17px 13px 0;
object-fit: cover; // 根据最大边保持比例
object-position: bottom left; // 显示左下角
}
改为根据最小边保持原比例
.pic {
height: 60px;
width: 60px;
margin: 10px 17px 13px 0;
object-fit: contain;
}