yanyan14231 / blob Goto Github PK
View Code? Open in Web Editor NEWmany ways about learning
many ways about learning
/^[A-Za-z0-9\u4e00-\u9fa5]+$/
getLength (str) {
if (str === null) return 0
if (typeof str !== 'string') {
str += ''
}
return str.replace(/[^\x00-\xff]/g, 'ab').length
}
vue.js
和elementUI
上传图片<el-form :label-position="labelPosition" label-width="150px" :model="formContent" :rules="rules" ref="formContent" status-icon>
<el-form-item label="收银台照片" prop="bannerPicture">
<el-upload
class="avatar-uploader"
:action="actionUrl"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:headers="headers"
>
<img v-if="formContent.bannerPicture" :src="formContent.bannerPicture" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
</el-form>
headers 设置上传的请求头部
action 请求的地址
on-success 文件上传成功时的钩子
on-preview 点击文件列表中已上传的文件时的钩子
on-remove 删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止上传。
show-file-list 是否显示已上传文件列表
data () {
return {
actionUrl: '', // 上传的地址
labelPosition: 'left',
formContent: {
bannerPicture: ''
},
rules: {
bannerPicture: [
{ required: true, message: '请选择图片', trigger: 'blur' }
]
},
headers: {
source: ''
}
}
},
methods: {
// 上传图片
handleAvatarSuccess (res, file) {
if (res.msg === '000') {
this.formContent.bannerPicture = '网址前缀' + res.url
} else {
this.notifyFailedSubmit(res.msg)
}
},
beforeAvatarUpload (file) {
const isPicType = ['image/jpeg', 'image/jpg', 'image/png', 'image/bmp'].indexOf(file.type) > -1
const isLt2M = file.size / 1024 / 1024 < 2
if (!isPicType) {
this.$message.error('上传图片只能是 JPG / JPEG/ PNG/ BMP 的格式!')
}
if (!isLt2M) {
this.$message.error('上传图片大小不能超过 2MB!')
}
return isPicType && isLt2M
},
handleRemove (file, fileList) {
},
handlePictureCardPreview (file) {
this.formContent.bannerPicture = file.url
},
notifyFailedSubmit (message) {
this.$notify.error({
title: '出错了',
message: message,
duration: 2000
})
}
}
<style rel="stylesheet/scss" lang="scss" scoped>
/*上传图片*/
.avatar-uploader {
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
border: 1px solid #dcdfe6;
border-radius: 6px;
}
.avatar-uploader-icon:hover{
border: 1px solid #c0c4cc;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
/*上传图片 end*/
</style>
以下图片取自 whatwg 的规范,可以说是最权威的图文解释了,详细参考原文
在正常情况下,即<script>
没有任何额外属性标记情况下,有几点共识:
js
脚本分为加载、解析、执行这几个步骤,简单对应到图中fetch(加载)和execution(解析并执行)js
的脚本加载(fetch)且执行(execution)会阻塞Dom
的渲染,因此js
放到最后头而defer和async的区别如下:
dom
解析完成后才会执行(execution),但会在DomContentLoaded
完成之前当以下 index.js 加载时,属性是 async 与 defer 时,输出有何不同?
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="index.js" defer></script>
<script>
console.log('Start')
document.addEventListener('DOMContentLoaded', () => {
console.log('DCL')
})
</script>
</body>
</html>
index.js
console.log('Async Script')
当
async
输出 Start 、 DCL 、 Async Script
当
defer
输出 Start 、 Async Script 、DCL
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
.box {
flex-direction: row | row-reverse | column | column-reverse;
}
row(默认值):主轴为水平方向,起点在左端
row-reverse:主轴为水平方向,起点在右端
column:主轴为垂直方向,起点在上沿
column-reverse:主轴为垂直方向,起点在下沿
.box{
flex-wrap: nowrap | wrap | wrap-reverse;
}
nowrap(默认):不换行
wrap:换行,第一行在上方
wrap-reverse:换行,第一行在下方
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
flex-start(默认值):左对齐
flex-end:右对齐
center: 居中
space-between:两端对齐,项目之间的间隔都相等
space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
flex-start:交叉轴的起点对齐
flex-end:交叉轴的终点对齐
center:交叉轴的中点对齐
baseline: 项目的第一行文字的基线对齐
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
flex-start:与交叉轴的起点对齐
flex-end:与交叉轴的终点对齐
center:与交叉轴的中点对齐
space-between:与交叉轴两端对齐,轴线之间的间隔平均分布
space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍
stretch(默认值):轴线占满整个交叉轴
order
flex-grow
flex-shrink
flex-basis
flex
align-self
.item {
order: <integer>;
}
.item {
flex-grow: <number>; /* default 0 */
}
如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍
.item {
flex-shrink: <number>; /* default 1 */
}
如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。
负值对该属性无效
.item {
flex-basis: <length> | auto; /* default auto */
}
它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
该属性可能取6个值,除了auto,其他都与align-items属性完全一致
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }
高德地图自带的,根据用户运动,画出运动轨迹,有起点和终点
用vue
以及element-ui
实现的,
页面布局
<div id="map"></div>
js部分
在mounted时候,加载地图,MP存在其他文件,mapKey是你地图的密钥
async mounted () {
await MP (this.mapKey)
this.mapRoute()
},
methods: {
mapRoute () {
let data = ‘获取到的数据’
// let data = [{lng: 116.478935, lat: 39.997761}, {lng: 116.478939, lat: 39.997825}, {lng: 116.478912, lat: 39.998549}, {lng: 116.478912, lat: 39.998549}, {lng: 116.478998, lat: 39.998555}]
let lineArr = []
for (let i = 0; i < data.length; i++) {
if (data[i].lat && data[i].lng) {
lineArr.push([data[i].lng, data[i].lat])
}
}
let map = new AMap.Map('map', {
center: lineArr[0],
zoom: 14
})
// 起始标记
let startIcon = new AMap.Icon({
// 图标尺寸
size: new AMap.Size(25, 34),
// 图标的取图地址
image: '//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png',
// 图标所用图片大小
imageSize: new AMap.Size(135, 40),
// 图标取图偏移量
imageOffset: new AMap.Pixel(-9, -3)
})
let startMarker = new AMap.Marker({
map: map,
position: lineArr[0],
icon: startIcon,
offset: new AMap.Pixel(-10, -13),
autoRotation: true
})
// 创建一个 icon
let endIcon = new AMap.Icon({
size: new AMap.Size(25, 34),
image: '//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png',
imageSize: new AMap.Size(135, 40),
imageOffset: new AMap.Pixel(-95, -3)
})
// 将 icon 传入 marker
let endMarker = new AMap.Marker({
position: new AMap.LngLat(lineArr[lineArr.length - 1][0], lineArr[lineArr.length - 1][1]),
icon: endIcon,
offset: new AMap.Pixel(-13, -30)
})
let polyline = new AMap.Polyline({
map: map,
path: lineArr,
showDir: true,
strokeColor: "#28F", //线颜色
// strokeOpacity: 1, //线透明度
// strokeWeight: 6, //线宽
// strokeStyle: "solid" //线样式
})
map.add([startMarker, endMarker])
map.setFitView() // 适应地图
}
}
css
#map {
width: 100%;
height: 100%;
}
######源码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="/Scripts/jquery-3.1.1.js"></script>
<style type="text/css">
.lineDiv {float: left; position: relative; height: 5px; background: #ccc; width: 300px; margin: 50px auto;
}
.lineDiv .minDiv { position: absolute; top: -20px; left: 0; width: 10px; height: 10px;background: #fff; border: 1px solid #d7000c; border-radius: 50%; cursor: pointer
}
.measure-drag{ clear: both; margin: 20px auto;}
.minus{float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; background: #ccc; cursor: pointer; margin: 40px 5px 0 0;}
.add{float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; background: #ccc; cursor: pointer; margin: 40px 0 0 5px;}
</style>
</head>
<body>
<center>
<h3>用鼠标拖动小方块<span class="msg">0</span>%</h3>
</center>
<div class="measure-drag">
<div class="minus">-</div>
<div class="lineDiv">
<p class="minDiv">
<span class="vals">0</span>
</p>
</div>
<div class="add">+</div>
</div>
<div class="measure-drag">
<div class="minus">-</div>
<div class="lineDiv">
<p class="minDiv">
<span class="vals">0</span>
</p>
</div>
<div class="add">+</div>
</div>
<div class="measure-drag">
<div class="minus">-</div>
<div class="lineDiv">
<p class="minDiv">
<span class="vals">0</span>
</p>
</div>
<div class="add">+</div>
</div>
<div class="measure-drag">
<div class="minus">-</div>
<div class="lineDiv">
<p class="minDiv">
<span class="vals">0</span>
</p>
</div>
<div class="add">+</div>
</div>
<div class="measure-drag">
<div class="minus">-</div>
<div class="lineDiv">
<p class="minDiv">
<span class="vals">0</span>
</p>
</div>
<div class="add">+</div>
</div>
<script>
$('.measure-drag').each(function(i){
drag($('.measure-drag .lineDiv')[i], $('.measure-drag .minDiv')[i], $(".measure-drag .vals")[i], $('.measure-drag .minus')[i], $('.measure-drag .add')[i]);
});
function drag(lineDiv, minDiv, vals, minus, add){
var msg = $(".msg")[0];
/**
* lineDiv长线条 minDiv小球 vals小球上的数值,即为所占的比例 minus减 add加
*/
var ifBool = false; //判断鼠标是否按下
//事件
var start = function(e) {
e.stopPropagation();
ifBool = true;
//console.log("鼠标按下")
}
var move = function(e) {
// console.log("鼠标拖动")
if(ifBool) {
if(!e.touches) { //兼容移动端
var x = e.clientX;
} else { //兼容PC端
var x = e.touches[0].pageX;
}
//var x = e.touches[0].pageX || e.clientX; //鼠标横坐标var x
var lineDiv_left = getPosition(lineDiv).left; //长线条的横坐标
var minDiv_left = x - lineDiv_left; //小方块相对于父元素(长线条)的left值
if(minDiv_left >= lineDiv.offsetWidth - 10) {
minDiv_left = lineDiv.offsetWidth - 10;
}
if(minDiv_left < 0) {
minDiv_left = 0;
}
//设置拖动后小方块的left值
minDiv.style.left = minDiv_left + "px";
msg.innerText = parseInt((minDiv_left / (lineDiv.offsetWidth - 10)) * 100);
vals.innerText = parseInt((minDiv_left / (lineDiv.offsetWidth - 10)) * 100);
}
}
var end = function(e) {
// console.log("鼠标弹起")
ifBool = false;
}
//鼠标按下方块
minDiv.addEventListener("touchstart", start);
minDiv.addEventListener("mousedown", start);
//拖动
window.addEventListener("touchmove", move);
window.addEventListener("mousemove", move);
//鼠标松开
window.addEventListener("touchend", end);
window.addEventListener("mouseup", end);
//获取元素的绝对位置
function getPosition(node) {
var left = node.offsetLeft; //获取元素相对于其父元素的left值var left
var top = node.offsetTop;
current = node.offsetParent; // 取得元素的offsetParent
// 一直循环直到根元素
while(current != null) {
left += current.offsetLeft;
top += current.offsetTop;
current = current.offsetParent;
}
return {
"left": left,
"top": top
};
}
//减
minus.onclick = function(){
vals.innerText --;
if(vals.innerText < 0){
vals.innerText = 0;
}
minDiv_left = vals.innerText/100 * (lineDiv.offsetWidth - 10);
minDiv.style.left = minDiv_left + "px";
};
//加
add.onclick = function(){
vals.innerText ++;
if(vals.innerText >= 100) {
vals.innerText = 100;
}
minDiv_left = vals.innerText/100 * (lineDiv.offsetWidth - 10);
minDiv.style.left = minDiv_left + "px";
};
}
</script>
</body>
</html>
###另一种范围是从-100 ~ 100
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="/Scripts/jquery-3.1.1.js"></script>
<style type="text/css">
.lineDiv { position: relative; height: 5px; background: #ccc; width: 300px; margin: 50px auto;
}
.lineDiv .minDiv { position: absolute; top: -20px; left: 50%; width: 10px; height: 10px;background: #fff; margin-left: -5px; border: 1px solid #d7000c; border-radius: 50%; cursor: pointer
}
</style>
</head>
<body>
<center>
<h3>用鼠标拖动小方块<span class="msg">0</span>%</h3>
</center>
<div class="measure-drag" style="clear: both; margin: 20px auto;">
<div class="minus" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">-</div>
<div class="lineDiv" style="float: left;">
<p class="minDiv">
<span class="vals">0</span>
</p>
</div>
<div class="add" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">+</div>
</div>
<div class="measure-drag" style="clear: both; margin: 20px auto;">
<div class="minus" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">-</div>
<div class="lineDiv" style="float: left;">
<p class="minDiv">
<span class="vals">0</span>
</p>
</div>
<div class="add" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">+</div>
</div>
<div class="measure-drag" style="clear: both; margin: 20px auto;">
<div class="minus" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">-</div>
<div class="lineDiv" style="float: left;">
<p class="minDiv">
<span class="vals">0</span>
</p>
</div>
<div class="add" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">+</div>
</div>
<div class="measure-drag" style="clear: both; margin: 20px auto;">
<div class="minus" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">-</div>
<div class="lineDiv" style="float: left;">
<p class="minDiv">
<span class="vals">0</span>
</p>
</div>
<div class="add" style="float: left; width: 20px; height: 20px; background: #ccc; cursor: pointer;">+</div>
</div>
<script>
$('.measure-drag').each(function(i){
drag($('.measure-drag .lineDiv')[i], $('.measure-drag .minDiv')[i], $(".measure-drag .vals")[i], $('.measure-drag .minus')[i], $('.measure-drag .add')[i]);
});
function drag(lineDiv, minDiv, vals, minus, add){
var msg = $(".msg")[0];
/**
* lineDiv长线条 minDiv小球 vals小球上的数值,即为所占的比例 minus减
add加
*/
var ifBool = false; //判断鼠标是否按下
//事件
var start = function(e) {
e.stopPropagation();
ifBool = true;
//console.log("鼠标按下")
}
var move = function(e) {
// console.log("鼠标拖动")
if(ifBool) {
if(!e.touches) { //兼容移动端
var x = e.clientX;
} else { //兼容PC端
var x = e.touches[0].pageX;
}
//var x = e.touches[0].pageX || e.clientX; //鼠标横坐标var x
var lineDiv_left = getPosition(lineDiv).left; //长线条的横坐标
var minDiv_left = x - lineDiv_left; //小方块相对于父元素(长线条)的left值
if(minDiv_left >= lineDiv.offsetWidth - 10) {
minDiv_left = lineDiv.offsetWidth - 10;
}
if(minDiv_left < 0) {
minDiv_left = 0;
}
//设置拖动后小方块的left值
minDiv.style.left = minDiv_left + "px";
msg.innerText =parseInt( (minDiv_left / (lineDiv.offsetWidth - 10)) * 100 * 2 - 100);
vals.innerText = parseInt((minDiv_left / (lineDiv.offsetWidth - 10)) * 100 * 2 - 100);
}
}
var end = function(e) {
// console.log("鼠标弹起")
ifBool = false;
}
//鼠标按下方块
minDiv.addEventListener("touchstart", start);
minDiv.addEventListener("mousedown", start);
//拖动
window.addEventListener("touchmove", move);
window.addEventListener("mousemove", move);
//鼠标松开
window.addEventListener("touchend", end);
window.addEventListener("mouseup", end);
//获取元素的绝对位置
function getPosition(node) {
var left = node.offsetLeft; //获取元素相对于其父元素的left值var left
var top = node.offsetTop;
current = node.offsetParent; // 取得元素的offsetParent
// 一直循环直到根元素
while(current != null) {
left += current.offsetLeft;
top += current.offsetTop;
current = current.offsetParent;
}
return {
"left": left,
"top": top
};
}
minus.onclick = function(){
vals.innerText --;
if(vals.innerText < -100){
vals.innerText = -100;
}
console.log(lineDiv.offsetWidth);
console.log(vals.innerText);
minDiv_left = (parseInt(vals.innerText) + 100)/200 * (lineDiv.offsetWidth - 10);
minDiv.style.left = minDiv_left + "px";
//vals.innerText = parseInt((minDiv_left / (lineDiv.offsetWidth - 10)) * 100);
};
add.onclick = function(){
vals.innerText ++;
if(vals.innerText >= 100) {
vals.innerText = 100;
}
minDiv_left = (parseInt(vals.innerText) + 100)/200 * (lineDiv.offsetWidth - 10);
minDiv.style.left = minDiv_left + "px";
//vals.innerText = a;
};
}
</script>
</body>
</html>
legend: {
selectedMode: false
}
在chart中添加 @click="handleEchart"
handleEchart (e) {
console.log(e)
}
<view class="echart-container">
<mpvue-echarts canvasId="chatSettled" ref="pieChart1" :echarts="echarts" @onInit="init10Chart" />
</view>
<view class="echart-container">
<mpvue-echarts canvasId="chatOrder" ref="pieChart2" :echarts="echarts" @onInit="init20Chart" />
</view>
高德地图自带的,根据用户输入的地址,进行模糊搜索,用户进行选择定位,根据用户输入的半径进行范围限定
用vue
以及element-ui
实现的
页面:
<div class="delivery-scope" v-show="range === '2'">
<div id="location"></div>
<div class="search">
<el-input
id="tip-input"
size="small"
class="search-input"
placeholder="请输入选择地址"
prefix-icon="el-icon-search"
v-model="address"
:clearable="true"
@input="mapLocation"
>
</el-input>
<ul class="list" v-show="searchMsg">
<li v-for="(item, index) in list" :key="index" @click="selectAddress(item)">{{item.name}}</li>
</ul>
</div>
<div class="radius">
以选择的中心点为中心,半径
<el-input
size="small"
class="search-input"
placeholder="请输入区域半径"
prefix-icon="el-icon-search"
v-model="radius"
:clearable="true"
>
</el-input>
m
</div>
</div>
css,没给完全,只有下拉框部分的
#location {
width: 100%;
height: 100%;
margin-top: 50px;
}
.search {
position: absolute;
left: 10px;
top: -40px;
.el-input {
width: 400px;
}
.list {
width: 380px;
// height: 300px;
background: #ffffff;
padding: 0 10px;
color: #333;
font-size: 14px;
}
li {
line-height: 40px;
cursor: pointer;
}
}
js
data () {
return {
mapKey: '', // 地图密钥
address: '', // 地址
list: [], // 下拉框
searchMsg: false, // 下拉框显示隐藏
radius: '', // 半径
selectData: {}, // 存储选中的值
lnglat: {}, // 记录上次的经纬度
}
},
async mounted () {
await MP (this.mapKey)
this.map()
},
methods: {
selectAddress (val) {
this.selectData = val
this.address = `${val.district}${val.name}`
this.searchMsg = false
this.map({
center: [val.location.lng, val.location.lat]
})
if (JSON.stringify(this.lnglat) !== '{}') {
this.mark('remove', this.lnglat)
}
this.lnglat = val.location
this.mark('add', val.location)
},
map (params) {
map = new AMap.Map('location', {
...params,
resizeEnable: true,
zoom: 14
})
},
mapLocation () {
map.plugin(['AMap.Autocomplete', 'AMap.PlaceSearch'], () => {
// 实例化Autocomplete
var autoOptions = {
city: '全国'
}
let autoComplete = new AMap.Autocomplete(autoOptions)
autoComplete.search(this.address, (status, result) => {
if (result && result.info === 'OK') {
this.list = result.tips
this.searchMsg = true
this.placeSearch(this.list.length && this.list[0].name)
}
})
})
},
placeSearch (value) {
let placeSearch = new AMap.PlaceSearch({
city: '全国',
map: map
})
placeSearch.search(value)
},
// 自己添加一个按钮,进行设置限制范围的操作
set () {
if (circle) {
circle.setMap(null)
}
circle = new AMap.Circle({
center: new AMap.LngLat(this.selectData.location.lng, this.selectData.location.lat), // 圆心位置
radius: this.radius, // 圆半径
borderWeight: 3,
strokeColor: "#FF33FF",
strokeOpacity: 1,
strokeWeight: 6,
strokeOpacity: 0.2,
fillOpacity: 0.4,
strokeStyle: 'dashed',
strokeDasharray: [10, 10],
// 线样式还支持 'dashed'
fillColor: '#1791fc',
zIndex: 50
})
circle.setMap(map)
map.setFitView([circle])
},
// 添加标记
mark (type, value) {
if (type === 'remove') {
return map.remove(marker)
}
marker = new AMap.Marker({
position: new AMap.LngLat(value.lng, value.lat),
title: '北京'
})
map.add(marker)
},
}
swiper
这个库的时候,一旦设置 loop:true 的时候,会遇到 dom 绑定事件无法触发的问题。swiper
会进行复制var mySwiper = new Swiper('.swiper-container', {
autoplay: true, //可选选项,自动滑动
loop: true,
pagination: {
el: '.swiper-pagination',
},
on: {
click: function () {
var realIndex = this.realIndex;
_this.handleClickSlide(realIndex);
}
}
})
function handleClickSlide (index) {
console.log(index)
}
创建的时候,加载js的文件
export default function MP (key) {
const JS1 = new Promise(function (resolve, reject) {
window.onload = function () {
resolve(window.AMap)
}
let script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'https://webapi.amap.com/maps?v=1.4.6&key=' + key + '&callback=onload'
script.onerror = reject
document.head.appendChild(script)
})
const JS2 = new Promise(function (resolve, reject) {
let script2 = document.createElement('script')
script2.type = 'text/javascript'
script2.src = 'https://webapi.amap.com/ui/1.0/main-async.js'
script2.onerror = reject
script2.onload = function () {
resolve('success')
}
document.head.appendChild(script2)
})
return Promise.all([JS1, JS2]).then(function (result) {
return result[0]
}).catch(e => {
console.log(e)
})
}
使用vue, mounted加载,MP是引入上面的函数
async mounted () {
await MP ('这是你的地图key')
},
customerControl.js
/*
* fabric.js Controls Extension
* for fabric.js current build
* Simon Kunz 09.02.2016 for pixolith
* Licensed under the MIT license.
*/
'use strict';
(function(window) {
var fabric = window.fabric || ( window.fabric = {} ),
minExtCompat = '1.6.0',
isVML = function() {
return typeof G_vmlCanvasManager !== 'undefined';
},
degreesToRadians = fabric.util.degreesToRadians,
cursorOffset = {
mt: 0, // n
tr: 1, // ne
mr: 2, // e
br: 3, // se
mb: 4, // s
bl: 5, // sw
ml: 6, // w
tl: 7 // nw
};
if (minExtCompat.localeCompare(window.fabric.version) > -1) {
console.warn('this extension might not be fully compatible with your version ' +
'of fabric.js (' + window.fabric.version + ').' +
'Consider using the latest compatible build of fabric.js (> ' + minExtCompat + ')'
);
}
fabric.util.object.extend(fabric.Object.prototype, {
/**
* When true, image icons are loaded via the drawImage method
* @type Boolean
* @default false
*/
useCustomIcons: false,
/**
* Sets a background-color for drawImage operations with transparency
* @type string
* @default transparent
*/
cornerBackgroundColor: 'transparent',
/**
* Sets the shape of the background for drawImage operations with transparency
* @type string
* @default rect
*/
cornerShape: '',
/**
* Inner Padding between Shape Background and drawn Image
* @type int
* @default rect
*/
cornerPadding: 0,
/**
* Set a custom corner icon
* @param {Object} obj settings and icon url.
* @param callback function
*/
customiseCornerIcons: function(obj, callback) {
var setting,
cornerConfig;
for (setting in obj) {
if (obj.hasOwnProperty(setting)) {
cornerConfig = {};
if (obj[setting].cornerShape !== undefined) {
this.cornerShape = obj[setting].cornerShape;
}
if (obj[setting].cornerBackgroundColor !== undefined) {
this.cornerBackgroundColor = obj[setting].cornerBackgroundColor;
}
if (obj[setting].borderColor !== undefined) {
this.borderColor = obj[setting].borderColor;
}
if (obj[setting].cornerSize !== undefined) {
this.cornerSize = obj[setting].cornerSize;
}
if (obj[setting].cornerPadding !== undefined) {
this.cornerPadding = obj[setting].cornerPadding;
}
if (obj[setting].icon !== undefined || Object.keys(obj)[0] === 'settings') {
this.useCustomIcons = true;
if (obj[setting].settings !== undefined) {
cornerConfig.settings = obj[setting].settings;
}
if (obj[setting].icon !== undefined) {
cornerConfig.icon = obj[setting].icon;
this.loadIcon(setting, cornerConfig, function() {
if (callback && typeof( callback ) === 'function') {
callback();
}
});
}
}
}
}
},
/**
* loads the icon image as an image src.
* @param {Object} corner to load an icon.
* @param cornerConfig as object containing icon url and corner specific settings
* @param callback function.
*/
loadIcon: function(corner, cornerConfig, callback) {
var self = this,
icon = new Image();
icon.onload = function() {
self[corner + 'Icon'] = this;
if (cornerConfig.settings) {
self[corner + 'Settings'] = cornerConfig.settings;
}
if (callback && typeof( callback ) === 'function') {
callback();
}
};
icon.onerror = function() {
fabric.warn(this.src + ' icon is not an image');
};
if (cornerConfig.icon.match(/^http[s]?:\/\//) || cornerConfig.icon.substring(0, 2) === '//') {
icon.crossOrigin = 'Anonymous';
}
icon.src = cornerConfig.icon;
},
/**
* copy of the setter method for our american friends.
* @param {Object} obj containing corner icon urls and settings.
*/
customizeCornerIcons: function(obj) {
this.customiseCornerIcons(obj);
},
/**
* Draws corners of an object's bounding box.
* Requires public properties: width, height
* Requires public options: cornerSize, padding
* @param {CanvasRenderingContext2D} ctx Context to draw on
* @return {fabric.Object} thisArg
* @chainable
*/
drawControls: function(ctx) {
if (!this.hasControls) {
return this;
}
var wh = this._calculateCurrentDimensions(),
width = wh.x,
height = wh.y,
scaleOffset = this.cornerSize,
left = -(width + scaleOffset) / 2,
top = -(height + scaleOffset) / 2,
methodName;
if (!this.useCustomIcons) {
ctx.lineWidth = 1;
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
ctx.strokeStyle = ctx.fillStyle = this.cornerColor;
if (!this.transparentCorners) {
ctx.strokeStyle = this.cornerStrokeColor;
}
methodName = this.transparentCorners ? 'stroke' : 'fill';
} else {
methodName = 'drawImage';
}
ctx.save();
// this._setLineDash(ctx, this.cornerDashArray, null);
// top-left
this._drawControl('tl', ctx, methodName,
left,
top,
this.tlIcon,
this.tlSettings
);
// top-right
this._drawControl('tr', ctx, methodName,
left + width,
top,
this.trIcon,
this.trSettings
);
// bottom-left
this._drawControl('bl', ctx, methodName,
left,
top + height,
this.blIcon,
this.blSettings
);
// bottom-right
this._drawControl('br', ctx, methodName,
left + width,
top + height,
this.brIcon,
this.brSettings
);
if (!this.get('lockUniScaling')) {
// middle-top
/*this._drawControl('mt', ctx, methodName,
left + width / 2,
top,
this.mtIcon,
this.mtSettings
);*/
// middle-bottom
/* this._drawControl('mb', ctx, methodName,
left + width / 2,
top + height,
this.mbIcon,
this.mbSettings
);*/
// middle-right
/*this._drawControl('mr', ctx, methodName,
left + width,
top + height / 2,
this.mrIcon,
this.mrSettings
);
*/
// middle-left
/* this._drawControl('ml', ctx, methodName,
left,
top + height / 2,
this.mlIcon,
this.mlSettings
);*/
}
// middle-top-rotate
if (this.hasRotatingPoint) {
/* this._drawControl('mtr', ctx, methodName,
left + width / 2,
top - this.rotatingPointOffset,
this.mtrIcon,
this.mtrSettings
);*/
}
ctx.restore();
return this;
},
/** Draw controls either with background-shape and color (transparency) or plain image (modified core method)
* @private
* {string} icon url of the control
*/
_drawControl: function(control, ctx, methodName, left, top, icon, settings) {
if (!this.isControlVisible(control)) {
return;
}
var size = this.cornerSize,
cornerStroke = this.cornerStrokeColor || 'transparent',
cornerBG = this.cornerBackgroundColor || 'black',
cornerShape = this.cornerShape || 'rect',
cornerPadding = this.cornerPadding || 10;
if (settings) {
if (settings.cornerSize) {
// Set the size, and also recalc left and top
left = left + size / 2 - settings.cornerSize / 2;
top = top + size / 2 - settings.cornerSize / 2;
size = settings.cornerSize;
}
cornerShape = settings.cornerShape || cornerShape;
cornerBG = settings.cornerBackgroundColor || cornerBG;
cornerPadding = settings.cornerPadding || cornerPadding;
cornerStroke = settings.cornerStrokeColor || cornerStroke;
}
if (this.useCustomIcons) {
if (cornerShape) {
ctx.globalAlpha = 1;
ctx.fillStyle = cornerBG;
ctx.lineWidth = 1;
ctx.strokeStyle = cornerStroke;
switch (cornerShape) {
case 'rect':
ctx.fillRect(left, top, size, size);
if (cornerStroke) {
ctx.strokeRect(left, top, size, size);
}
break;
case 'circle':
ctx.beginPath();
ctx.arc(left + size / 2, top + size / 2, size / 2, 0, 2 * Math.PI);
ctx.fill();
if (cornerStroke) {
ctx.stroke();
}
ctx.closePath();
break;
}
if (icon !== undefined) {
ctx[methodName](
icon,
left + cornerPadding / 2,
top + cornerPadding / 2,
size - cornerPadding,
size - cornerPadding
);
}
} else {
if (icon !== undefined) {
ctx[methodName](
icon,
left,
top,
size,
size
);
}
}
} else {
isVML() || this.transparentCorners || ctx.clearRect(left, top, size, size);
ctx[methodName + 'Rect'](left, top, size, size);
if (!this.transparentCorners && cornerStroke) {
ctx.strokeRect(left, top, size, size);
}
}
},
});
fabric.util.object.extend(fabric.Canvas.prototype, {
/**
* When true, actions can be overwritten
* @type Boolean
* @default false
*/
overwriteActions: false,
/**
* When true, cursors are fixed
* @type Boolean
* @default false
*/
fixedCursors: false,
/**
* setter Method for actions and cursors.
* @param {Object} obj containing corner action and cursor url/type.
*/
customiseControls: function(obj) {
var setting;
for (setting in obj) {
if (obj.hasOwnProperty(setting)) {
if (obj[setting].action !== undefined) {
this.overwriteActions = true;
this.setCustomAction(setting, obj[setting].action);
}
if (obj[setting].cursor !== undefined) {
this.fixedCursors = true;
this.setCustomCursor(setting, obj[setting].cursor);
}
}
}
},
/**
* loads the icon image as an image src.
* @param {Object} corner to load an icon.
* @param action as a string.
*/
setCustomAction: function(corner, action) {
this[corner + 'Action'] = action;
},
/**
* loads the icon image as an image src.
* @param {Object} corner to load an icon.
* @param cursorUrl as a string.
*/
setCustomCursor: function(corner, cursorUrl) {
this[corner + 'cursorIcon'] = cursorUrl;
},
/**
* copy of the setter method for our american friends.
* @param {Object} obj containing corner action and cursor url/type.
*/
customizeControls: function(obj) {
this.customiseControls(obj);
},
/**
* @private
*/
_getActionFromCorner: function(target, corner, e) {
if (!corner) {
return 'drag';
}
if (corner) {
if (this[corner + 'Action'] && this.overwriteActions) {
switch (corner) {
//case 'mtr':
// return this[corner + 'Action'] || 'rotate';
case 'ml':
case 'mr':
if (e[this.altActionKey]) {
return e[this.altActionKey] ? 'skewY' : 'scaleX';
}
return this[corner + 'Action'];
case 'mt':
case 'mb':
if (e[this.altActionKey]) {
return e[this.altActionKey] ? 'skewY' : 'scaleY';
}
return this[corner + 'Action'];
default:
return this[corner + 'Action'] || 'scale';
}
} else {
switch (corner) {
// case 'mtr':
// return 'rotate';
case 'ml':
case 'mr':
return e[this.altActionKey] ? 'skewY' : 'scaleX';
case 'mt':
case 'mb':
return e[this.altActionKey] ? 'skewX' : 'scaleY';
default:
return 'scale';
}
}
}
return false;
},
/**
* @private
* @param {Event} e Event object
* @param {fabric.Object} target
*/
_setupCurrentTransform: function(e, target) {
if (!target) {
return;
}
var pointer = this.getPointer(e),
corner = target._findTargetCorner(this.getPointer(e, true)),
action = this._getActionFromCorner(target, corner, e),
origin = this._getOriginFromCorner(target, corner);
if (typeof action === 'function') {
action.call(this, e, target);
// as of fabric 1.7.11 object cache will try to slice the action to check for scale so we need to convert this to a string
action = 'void';
}
this._currentTransform = {
target: target,
action: action,
corner: corner,
scaleX: target.scaleX,
scaleY: target.scaleY,
skewX: target.skewX,
skewY: target.skewY,
offsetX: pointer.x - target.left,
offsetY: pointer.y - target.top,
originX: origin.x,
originY: origin.y,
ex: pointer.x,
ey: pointer.y,
lastX: pointer.x,
lastY: pointer.y,
left: target.left,
top: target.top,
theta: degreesToRadians(target.angle),
width: target.width * target.scaleX,
mouseXSign: 1,
mouseYSign: 1,
shiftKey: e.shiftKey,
altKey: e[this.centeredKey],
};
this._currentTransform.original = {
left: target.left,
top: target.top,
scaleX: target.scaleX,
scaleY: target.scaleY,
skewX: target.skewX,
skewY: target.skewY,
originX: origin.x,
originY: origin.y,
};
if (action === 'remove') {
this._removeAction(e, target);
}
if (action === 'moveUp') {
this._moveLayerUpAction(e, target);
}
if (action === 'moveDown') {
this._moveLayerDownAction(e, target);
}
if (typeof action === 'object') {
if (Object.keys(action)[0] === 'rotateByDegrees') {
this._rotateByDegrees(e, target, action.rotateByDegrees);
}
}
this._resetCurrentTransform();
},
/**
* Custom remove object action
* @private
* @param {Event} e Event object
* @param {fabric.Object} target
*/
_removeAction: function(e, target) {
var _this = this;
if (this.getActiveGroup() && this.getActiveGroup() !== 'undefined') {
this.getActiveGroup().forEachObject(function(o) {
o.off();
o.remove();
});
this.discardActiveGroup();
// as of fabric 1.6.3 necessary for reasons..
setTimeout(function() {
_this.deactivateAll();
}, 0);
} else {
target.off();
target.remove();
setTimeout(function() {
_this.deactivateAll();
}, 0);
}
},
/**
* Custom move up object action
* @private
* @param {Event} e Event object
* @param {fabric.Object} target
*/
_moveLayerUpAction: function(e, target) {
if (this.getActiveGroup() && this.getActiveGroup() !== 'undefined') {
this.getActiveGroup().forEachObject(function(o) {
o.bringForward();
});
} else {
target.bringForward();
}
},
/**
* Custom move down object action
* @private
* @param {Event} e Event object
* @param {fabric.Object} target
*/
_moveLayerDownAction: function(e, target) {
if (this.getActiveGroup() && this.getActiveGroup() !== 'undefined') {
this.getActiveGroup().forEachObject(function(o) {
o.sendBackwards();
});
} else {
target.sendBackwards();
}
},
/**
* Custom move down object action
* @private
* @param {Event} e Event object
* @param {fabric.Object} target
* @param {Integer} value of rotation
*/
_rotateByDegrees: function(e, target, value) {
var angle = parseInt(target.getAngle()) + value,
needsOriginRestore = false;
if (( target.originX !== 'center' || target.originY !== 'center' ) && target.centeredRotation) {
this._setOriginToCenter(target);
needsOriginRestore = true;
}
angle = angle > 360 ? angle - 360 : angle;
if (this.getActiveGroup() && this.getActiveGroup() !== 'undefined') {
this.getActiveGroup().forEachObject(function(obj) {
obj
.setAngle(angle)
.setCoords();
});
} else {
target
.setAngle(angle)
.setCoords();
}
if (needsOriginRestore) {
this._setCenterToOrigin(target);
}
this.renderAll();
},
/**
* Sets either the standard behaviour cursors or if fixedCursors is true, tries to set a custom cursor
* either by using an icon or a build-in cursor. Cursor icon extensions are matched with a regular expression.
* @private
* {string} corner name
* {target} event handler of the hovered corner
*/
_setCornerCursor: function(corner, target, e) {
var iconUrlPattern = /\.(?:jpe?g|png|gif|jpg|jpeg|svg)$/;
if (this.fixedCursors && this[corner + 'cursorIcon']) {
if (this[corner + 'cursorIcon'].match(iconUrlPattern)) {
this.setCursor('url(' + this[corner + 'cursorIcon'] + '), auto');
} else {
if (this[corner + 'cursorIcon'] === 'resize') {
this.setCursor(this._getRotatedCornerCursor(corner, target, e));
} else {
this.setCursor(this[corner + 'cursorIcon']);
}
}
} else {
if (corner in cursorOffset) {
this.setCursor(this._getRotatedCornerCursor(corner, target, e));
} else if (corner === 'mtr' && target.hasRotatingPoint) {
this.setCursor(this.rotationCursor);
} else {
this.setCursor(this.defaultCursor);
return false;
}
}
return false;
},
});
if (typeof exports !== 'undefined') {
module.exports = this;
}
})(window);
添加四角图片及四角的作用
fabric.Canvas.prototype.customiseControls({
settings: {
cornerSize: 32,
borderColor: '#05121c'
},
tr: {
action: 'remove',
cursor: 'pointer'
},
br: {
action: 'scale',
cursor: 'pointer'
},
tl: {
action: 'rotate',
cursor: 'pointer'
},
bl: {
action: '',
cursor: 'pointer'
}
});
fabric.Object.prototype.customiseCornerIcons({
tl: {
icon: '../images/details/icons/icon_rotate.png'
},
br: {
icon: '../images/details/icons/icon_escal.png'
},
tr: {
icon: '../images/details/icons/icon_remove.png'
},
bl: {
icon: '../images/details/icons/icon_mover.png'
}
}, function () {
canvas.renderAll();
});
这是为了选中后又重新渲染后,点击每一个图片还会被选中(就是添加四角)
//设置item的四角矩形及是否有旋转
function setRotate(item) {
item.set('hasRotatingPoint', false);
item.customiseCornerIcons({
settings: {
borderColor: '#061101',
cornerSize: 32,
cornerShape: 'rect',
cornerPadding: 10
},
tl: {
icon: '../images/details/icons/icon_rotate2.png'
},
br: {
icon: '../images/details/icons/icon_escal2.png'
},
tr: {
icon: '../images/details/icons/icon_remove2.png'
},
bl: {
icon: '../images/details/icons/icon_mover2.png'
}
}, function () {
canvas.renderAll();
});
}
控制绘画区域的鼠标移入移出,以及选中元素删除进行的操作
//控制绘画区域的鼠标移入移出,以及选中元素删除进行的操作
canvas.on('mouse:over', function (options) {
});
canvas.on('mouse:out', function (options) {
});
canvas.on('object:removed', function (item) {
})
选中某个(图片、文字)时进行操作
//选中某个(图片、文字)时进行操作
canvas.on('object:selected', function (e) {
$.each(canvas.getObjects(), function (m, item) {
for (var n in item) {
if (n == 'active' && item[n] == true) {
if (item.active == true) {
setRotate(item);//设置item的四角矩形及是否有旋转
if ($('#view').css('backgroundColor') == 'rgba(0, 0, 0, 0)') {
item.set('borderColor', '#303030');
canvas.renderAll();
} else {
judgeBorderColor($('#view').css('backgroundColor'), item);
canvas.renderAll();
}
//判断当前选中的在哪个tab中
$(this)[0].text ? tabGet(2) : null;
$(this)[0].paths ? (item.flag == 1 ? tabGet(0) : tabGet(1)) : null;
$(this)[0].filters ? tabGet(3) : null;
//getPrice();
$('#dis-text').val(item.text); //设置文字输入框的值
_this = item;
//选择字体
$('.sel-font').on('change', function (e) {
_this.fontFamily = $(this).val();
canvas.renderAll();
});
$('#dis-text').on('keyup', function (e) {
_this.text = e.target.value;
canvas.renderAll();
});
selColor('#picker2'); //选择字体的颜色
selColor('#picker'); //选择图片二的颜色
selColor('#picker5'); //选择图片一的颜色
//选中字体工具的图片
$('.font-tools img').each(function (n) {
$(this).on('mousedown', function (e) {
n < 3 ? _this.textAlign = fontToolsImg[n] : null;
n == 3 ? (_this.fontWeight = _this.fontWeight == 'normal' ? fontToolsImg[n] : 'normal') : null;
n == 4 ? (_this.fontStyle = _this.fontStyle != fontToolsImg[n] ? _this.fontStyle = fontToolsImg[n] : 'normal') : null;
canvas.renderAll();
});
});
//按delete键可以删除
document.onkeydown = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
if (e && e.keyCode == 46) {
canvas.remove(_this); //删除
canvas.renderAll();
}
};
} else {
return false;
}
}
}
});
});
var getElementCanvas = (function () {
var fontFamily = ['宋体','Bookshelf Symbol 7', 'Calibri', 'Cambria', 'Cambria Math', 'Consolas', 'Georgia', 'HoloLens MDL2 Assets', 'Microsoft YaHei UI', 'MS Outlook', 'MS Reference Specialty', 'MT Extra', 'Segoe MDL2 Assets', 'Segoe UI Emoji', 'Segoe UI Symbol', 'SimSun-ExtB', 'Symbol', 'Verdana', 'Webdings', 'Wingdings', 'Wingdings 2', 'Wingdings 3', '等线', '方正兰亭超细黑简体', '方正舒体', '方正姚体', '仿宋', '黑体', '华文彩云', '华文仿宋', '华文行楷', '华文琥珀', '华文楷体', '华文隶书', '华文宋体', '华文细黑', '华文新魏', '华文中宋', '楷体', '隶书', '微软雅黑', '新宋体', '幼圆'];
var fontToolsImg = ['left', 'center', 'right', 'bold', 'italic'];
//添加字体
$.each(fontFamily, function (i) {
$('.sel-font').append('<option>' + fontFamily[i] + '</option>');
});
//装饰品鼠标滑动的切换
$('.dec-select li').on('mouseover', function () {
$('.dec-select li').removeClass('activeTab');
$(this).addClass('activeTab');
$('.dec-content li').addClass('dis');
$('.dec-content li').eq($(this).index()).removeClass('dis');
});
//将图片添加到衣服上
var canvas = this.__canvas = new fabric.Canvas('design-border');
fabric.Canvas.prototype.customiseControls({
tr: {
action: 'remove',
cursor: 'pointer'
},
br: {
action: 'scale',
cursor: 'pointer'
},
tl: {
action: 'rotate',
cursor: 'pointer'
},
bl: {
action: '',
cursor: 'pointer'
}
});
fabric.Object.prototype.customiseCornerIcons({
tl: {
icon: '../images/details/icons/icon_rotate2.png'
},
br: {
icon: '../images/details/icons/icon_escal2.png'
},
tr: {
icon: '../images/details/icons/icon_remove2.png'
},
bl: {
icon: '../images/details/icons/icon_mover2.png'
}
}, function () {
canvas.renderAll();
});
//添加四角矩形框,判断是否进行删除
function setPic(obj, isDelete) {
obj.customiseCornerIcons({
settings: {
cornerSize: 32,
borderColor: '#05121c'
},
tl: {
icon: '../images/details/icons/icon_rotate2.png'
},
br: {
icon: '../images/details/icons/icon_escal2.png'
},
tr: {
icon: '../images/details/icons/icon_remove2.png'
},
bl: {
icon: '../images/details/icons/icon_mover2.png'
}
}, function () {
canvas.renderAll();
});
canvas.add(obj);
canvas.setActiveObject(obj);
if (isDelete) {
var arr = canvas.getObjects();
var obj = arr[canvas.getObjects().length - 1];
canvas.remove(obj);
if ($('.design-border-blue').css('display') == 'block') {
$('.design-border-blue').css('display', 'none');
}
}
}
//将图片添加到衣服上
function addImg(element, imgInstance, num) {
for (var n = 0; n < element.length; n++) {
(function (n) {
element[n].onclick = function () {
if ($('.design-border-blue').css('display') == 'none') {
$('.design-border-blue').css('display', 'block');
}
fabric.loadSVGFromURL(element[n]['src'], function (objects, options) {
imgInstance[n] = fabric.util.groupSVGElements(objects, options);
if (options.width >= options.height) {
imgInstance[n].scale(100 / options.width);
}else {
imgInstance[n].scale(100 / options.height);
}
imgInstance[n].set({
left: 80,
top: 100,
fill: '#000000',
originX: 'center',
originY: 'center',
hasRotatingPoint: false,
flag: num,
id: element[n].getAttribute("data-id"),
price: element[n].getAttribute('data-pri')
});
setPic(imgInstance[n]);
});
/*if (element[n]['src'].indexOf('.svg') > 0) {
} else {
var img = new fabric.Image(element[n]['src'], {
left: 100,
top: 150,
scale: 6.8,
originX: 'center',
originY: 'center',
hasRotatingPoint: false
});
setPic(img);
} */
}
})(n);
}
}
//将文字添加到衣服上
var txt = $('#dis-text');
var txtInstance = null;
$('.design-btn-font').on('click', function () {
if ($('.design-border-blue').css('display') == 'none') {
$('.design-border-blue').css('display', 'block');
}
txtInstance = new fabric.IText(txt.val(), {
left: 80,
top: 100,
fontFamily: 'Comic Sans',
fontSize: 20,
fill: '#000000',
//id: 'addText',
originX: 'center',
originY: 'center',
hasRotatingPoint: false
});
setPic(txtInstance);
});
//上传添加图片
var uploader = WebUploader.create({
// 选完文件后,是否自动上传。
auto: true,
// swf文件路径
swf: '../js/Uploader.swf',
// 文件接收服务端。
server: 'http://webuploader.duapp.com/server/fileupload.php',
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: '#filePicker',
// 只允许选择图片文件。
accept: {
title: 'Images',
extensions: 'gif,jpg,jpeg,bmp,png',
mimeTypes: 'image/*'
},
resize: false,
compress: false,
thumb: {
allowMagnify: false,
crop: false,
type: '' // 这样会保证png格式的透明背景不会变成黑色
}
});
var oImg = null;
// 当有文件添加进来的时候
uploader.on('fileQueued', function (file) {
var $li = $(
'<div id="' + file.id + '" class="file-item thumbnail">' +
'<img>' +
// '<div class="info">' + file.name + '</div>' +
'</div>'
),
$img = $li.find('img');
// $list为容器jQuery实例
$('#fileList').append($li);
// 创建缩略图
// 如果为非图片文件,可以不用调用此方法。
// thumbnailWidth x thumbnailHeight 为 100 x 100
uploader.makeThumb(file, function (error, src) {
if (error) {
$img.replaceWith('<span>不能预览</span>');
return;
}
$img.attr('src', src);
//设置图片,将其显示在4*4的框中
var w = parseInt(file._info.width);
var h = parseInt(file._info.height);
var r = w / h;
if (w <= h) {
$img.css({ 'width': 3.26 * r + 'rem', 'height': '3.26rem', 'marginLeft': (3.26 - 3.26 * r) / 2 + 'rem' });
} else {
$img.css({ 'width': '3.26rem', 'height': 3.26 / r + 'rem', 'marginTop': (3.26 - 3.26 / r) / 2 + 'rem' });
}
}, 1500, 1500);
});
uploader.on('filesQueued', function () {
$('#fileList img').each(function (j, item) {
$(this).unbind('click').on('click', function () {
oImg = new fabric.Image(item, {
left: 80,
top: 110,
originX: 'center',
originY: 'center',
hasRotatingPoint: false
});
setPic(oImg);
});
});
});
// 文件上传过程中创建进度条实时显示。
/* uploader.on('uploadProgress', function (file, percentage) {
var $li = $('#' + file.id),
$percent = $li.find('.progress span');
// 避免重复创建
if (!$percent.length) {
$percent = $('<p class="progress"><span></span></p>')
.appendTo($li)
.find('span');
}
$percent.css('width', percentage * 100 + '%');
});*/
/*// 文件上传成功,给item添加成功class, 用样式标记上传成功。
uploader.on( 'uploadSuccess', function( file ) {
$( '#'+file.id ).addClass('upload-state-done');
});
// 文件上传失败,显示上传出错。
uploader.on( 'uploadError', function( file ) {
var $li = $( '#'+file.id ),
$error = $li.find('div.error');
// 避免重复创建
if ( !$error.length ) {
$error = $('<div class="error"></div>').appendTo( $li );
}
$error.text('上传失败');
});
// 完成上传完了,成功或者失败,先删除进度条。
uploader.on( 'uploadComplete', function( file ) {
$( '#'+file.id ).find('.progress').remove();
});*/
//设置item的四角矩形及是否有旋转
function setRotate(item) {
item.set('hasRotatingPoint', false);
item.customiseCornerIcons({
settings: {
borderColor: '#061101',
cornerSize: 32,
cornerShape: 'rect',
cornerPadding: 10
},
tl: {
icon: '../images/details/icons/icon_rotate2.png'
},
br: {
icon: '../images/details/icons/icon_escal2.png'
},
tr: {
icon: '../images/details/icons/icon_remove2.png'
},
bl: {
icon: '../images/details/icons/icon_mover2.png'
}
}, function () {
canvas.renderAll();
});
}
//判断当前选中的在哪个tab中
function tabGet(i) {
$('.dec-select li').removeClass('activeTab');
$('.dec-select li').eq(i).addClass('activeTab');
$('.dec-content li').addClass('dis');
$('.dec-content li').eq(i).removeClass('dis');
}
//选择字体、图片的颜色
function selColor(id) {
$(id).colpick({
submit: 0,
onChange: function (hsb, hex, rgb, el, bySetColor) {
$(el).css('border-color', '#' + hex);
if (!bySetColor) $(el).val(hex);
$(id).css('background', '#' + hex);
_this.set('fill', '#' + hex);
canvas.renderAll();
}
}).keyup(function () {
$(this).colpickSetColor(this.value);
});
}
//控制绘画区域的显示隐藏
canvas.on('mouse:over', function (options) {
//console.log(options.e.clientX, options.e.clientY); // 打印坐标
if (isDesign) {
$('.design-border-blue').css('display', 'block');
}
});
canvas.on('mouse:out', function (options) {
//console.log(options.e.clientX, options.e.clientY); // 打印坐标
if (isDesign) {
$('.design-border-blue').css('display', 'none');
}
});
canvas.on('object:removed', function (item) {
if (item.target.pId === true) {
item.target.pId = false
} else {
designUploadId.splice(designUploadId.indexOf(item.target.id), 1)
console.log(designUploadId)
getPrice();
}
})
//canvas.on('mouse:up', function () {
// var currentId = [];
// var objArr = canvas.getObjects();
// objArr.forEach(function (item, index) {
// currentId.push(item.id);
// })
// clearCopy(currentId);
// //getPrice();
//})
//function clearCopy(currentId) {
// var len = designUploadId.length;
// designUploadId.splice(0, designUploadId.length);
// currentId.forEach(function (item, index) {
// designUploadId.push(item);
// })
// console.log(designUploadId.length);
// if (designUploadId.length != len) {
// designUploadId.isChange = 1;
// }
//}
$(document).on('click', '.on-pics', function () {
designUploadId.push($(this).attr('data-id'));
console.log(designUploadId)
getPrice();
})
//选中某个(图片、文字)时进行操作
canvas.on('object:selected', function (e) {
$('.design-border-blue').css('display', 'block');
$.each(canvas.getObjects(), function (m, item) {
for (var n in item) {
if (n == 'active' && item[n] == true) {
if (item.active == true) {
setRotate(item);//设置item的四角矩形及是否有旋转
if ($('#view').css('backgroundColor') == 'rgba(0, 0, 0, 0)') {
item.set('borderColor', '#303030');
canvas.renderAll();
} else {
judgeBorderColor($('#view').css('backgroundColor'), item);
canvas.renderAll();
}
//判断当前选中的在哪个tab中
$(this)[0].text ? tabGet(2) : null;
$(this)[0].paths ? (item.flag == 1 ? tabGet(0) : tabGet(1)) : null;
$(this)[0].filters ? tabGet(3) : null;
//getPrice();
$('#dis-text').val(item.text); //设置文字输入框的值
_this = item;
//选择字体
$('.sel-font').on('change', function (e) {
_this.fontFamily = $(this).val();
canvas.renderAll();
});
$('#dis-text').on('keyup', function (e) {
_this.text = e.target.value;
canvas.renderAll();
});
selColor('#picker2'); //选择字体的颜色
selColor('#picker'); //选择图片二的颜色
selColor('#picker5'); //选择图片一的颜色
//选中字体工具的图片
$('.font-tools img').each(function (n) {
$(this).on('mousedown', function (e) {
n < 3 ? _this.textAlign = fontToolsImg[n] : null;
n == 3 ? (_this.fontWeight = _this.fontWeight == 'normal' ? fontToolsImg[n] : 'normal') : null;
n == 4 ? (_this.fontStyle = _this.fontStyle != fontToolsImg[n] ? _this.fontStyle = fontToolsImg[n] : 'normal') : null;
canvas.renderAll();
});
});
//按delete键可以删除
document.onkeydown = function (event) {
var e = event || window.event || arguments.callee.caller.arguments[0];
if (e && e.keyCode == 46) {
canvas.remove(_this); //删除
canvas.renderAll();
}
};
} else {
return false;
}
}
}
});
});
//判断衣服颜色深浅,显示不同的边框颜色
function judgeColor(rgb) {
var RgbValue = rgb.replace("rgb(", "").replace(")", "");
var RgbValueArry = RgbValue.split(",");
var $grayLevel = RgbValueArry[0] * 0.299 + RgbValueArry[1] * 0.587 + RgbValueArry[2] * 0.114;
$grayLevel >= 192 ? $('.design-border-blue').css('border', '1px solid #303030') : $('.design-border-blue').css('border', '1px solid #dedede');
}
//边框颜色改变
function judgeBorderColor(rgb, item) {
var RgbValue = rgb.replace("rgb(", "").replace(")", "");
var RgbValueArry = RgbValue.split(",");
var $grayLevel = RgbValueArry[0] * 0.299 + RgbValueArry[1] * 0.587 + RgbValueArry[2] * 0.114;
$grayLevel >= 192 ? item.set('borderColor', '#303030') : item.set('borderColor', '#dedede');
}
//衣服颜色列表
$('.pro-colors-list li').each(function () {
$(this).on('click', function () {
$('#view').css('background', $(this).css('backgroundColor'));
judgeColor($(this).css('backgroundColor'));
$('.design-border-blue').css('display', 'none');
canvas.renderAll();
});
});
//衣服颜色画板
$('#picker3').colpick({
submit: 0,
onChange: function (hsb, hex, rgb, el, bySetColor) {
$('#view').css('backgroundColor', '#' + hex);
judgeColor('rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')');
$('.design-border-blue').css('display', 'none');
canvas.renderAll();
}
}).keyup(function () {
$(this).colpickSetColor(this.value);
});
//显示隐藏
function selDisplay(ele) {
$(ele).css('display') == 'block' ? $(ele).css('display', 'none') : null;
}
//点击空白处选中的框也可以消失
$(document).on('mousedown', function () {
if (canvas.getActiveObject()) {
canvas.getActiveObject().active = false;
canvas.renderAll();
//创建一个,并删除,使其选中
fabric.loadSVGFromURL('../images/flower.svg', function (objects, options) {
a = fabric.util.groupSVGElements(objects, options);
a.set({
left: 100,
top: 100,
fill: '#000000',
originX: 'center',
originY: 'center',
hasRotatingPoint: false,
flag: 1,
pId: true
});
setPic(a, true);
});/* */
/* console.log(canvas.getActiveObject());
var item = canvas.getActiveObject();
//判断当前选中的在哪个tab中
item.text ? tabGet(2) : null;
item.paths ? (item.flag == 1 ? tabGet(0) : tabGet(1)) : null;
item.filters ? tabGet(3) : null; */
// setRotate(item);
}
selDisplay('.colpick');
selDisplay('#colorpicker_1');
selDisplay('#colorpicker_2');
selDisplay('#colorpicker_3');
selDisplay('#colorpicker_4');
selDisplay('.design-border-blue');
});
//将饰品修饰的那部分
$('.dec-content').on('mousedown', function (e) {
e.stopPropagation();
});
/*var json = {"objects":[{"type":"i-text","originX":"center","originY":"center","left":120.78,"top":117.06,"width":27.73,"height":22.6,"fill":"#1d85cf","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":2.45,"scaleY":2.45,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"ffff","fontSize":20,"fontWeight":"normal","fontFamily":"Comic Sans","fontStyle":"","lineHeight":1.16,"textDecoration":"","textAlign":"left","textBackgroundColor":"","charSpacing":0,"styles":{}}]}
canvas.loadFromJSON(json, function () {
console.log(json);
canvas.renderAll();
});*/
//保存canvas上面的内容 加载json 不提交的
/*$('.take-count .btn-common').eq(0).on('click', function () {
console.log(canvas.toJSON());
var json = JSON.stringify(canvas.toJSON());
canvas.clear();
$(this).click(function () {
canvas.loadFromJSON(json, function () {
console.log(json);
canvas.renderAll();
});
});
}); */
//获取图库一二中的图片
function getAjaxImg(url, num) {
var key ;
if (getUrlParam("ProductId")!=null ) {
key = getUrlParam("ProductId");
} else {
key = getUrlParam("key");
}
// alert(key);
$.ajax({
url: '/Details/' + url + '?productId=' +key,//window.location.search.substr(1).split('=')[1],
type: 'post',
success: function (data) {
// console.log(data);
$.each(data, function (i) {
$('.online-pic' + num).append('<img class="left on-pics" data-pri="' + data[i]['price'] + '" data-id="' + data[i]['Id'] + '" src="http://api.quandz.com' + data[i]['Image'] + '" alt="" />');
});
addImg($('.online-pic' + num + ' img'), [], num); //可以点击添加图片到衣服上
},
error: function () {
console.log('error');
}
});
}
getAjaxImg('GetImageI', 1); //图库一
getAjaxImg('GetImageII', 2);//图库二
return canvas;
})();
/^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57]|19[89]|166)[0-9]{8}$/
/0\d{2,3}-\d{7,8}/
val.replace(/\B(?=(?:\d{3})+\b)/g, ',')
val.match(/[\u4e00-\u9fa5]/g).join('')
eg: '这是AB一段CD文字'.match(/[\u4e00-\u9fa5]/g).join('') ==== 这是一段文字
val.replace(/[^0-9]/ig, '')
eg: '这是问问2545554'.replace(/[^0-9]/ig, '') ==== 2545554
两者之间的主要区别在于,使用回调方法时,我们通常只是将回调传递给一个函数,该函数将在完成时被调用以获取某些结果。但是,在Promise中,您将回调附加在返回的Promise对象上。
原文链接
CallBacks
function getMoneyBack(money, callback) {
if (typeof money !== 'number') {
callback(null, new Error('money is not a number'))
} else {
callback(money)
}
}
const money = getMoneyBack(1200)
console.log(money)
Promises
function getMoneyBack(money) {
return new Promise((resolve, reject) => {
if (typeof money !== 'number') {
reject(new Error('money is not a number'))
} else {
resolve(money)
}
})
}
getMoneyBack(1200).then((money) => {
console.log(money)
})
200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201 (已创建) 请求成功并且服务器创建了新的资源。
202 (已接受) 服务器已接受请求,但尚未处理。
203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206 (部分内容) 服务器成功处理了部分 GET 请求。
300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
400 (错误请求) 服务器不理解请求的语法。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
405 (方法禁用) 禁用请求中指定的方法。
406 (不接受) 无法使用请求的内容特性响应请求的网页。
407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408 (请求超时) 服务器等候请求时发生超时。
409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。
500 (服务器内部错误) 服务器遇到错误,无法完成请求。
501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
让链接生成二维码,生成的二维码可以进行下载,其中生成的二维码中间可以放上一个logo,二维码周围是一个背景图,主要使用 vue.js
QRCode
VueQr
html2canvas
实现的。
首先生成二维码,然后html2canvas
将背景图和二维码转成新的图片,并进行下载
<div class="content" id="content">
<vue-qr
v-if="qrcodeUrl"
:logoSrc="logo"
:text="qrcodeUrl"
:whiteMargin="true"
:size="400"
:dotScale="1"
:logoScale="0.2"
:logoMargin="10"
logoBackgroundColor="#fff"
:correctLevel="3"
></vue-qr>
<img v-if="!qrcodeUrl" :src="newSrc" alt="">
</div>
import QRCode from 'qrcode'
import VueQr from 'vue-qr'
import html2canvas from 'html2canvas'
其中qrcodeBG 和 logo是两张背景图,可以引进来
components: {
VueQr,
QRCode
},
data () {
return {
codes: '',
imgBgSrc: qrcodeBG,
downloadInfo: '',
qrcodeUrl: '', // 这是链接的地址
newSrc: '',
logo: logo
}
},
mounted () {
this.qrcodeScan(this.qrcodeUrl)
},
methods: {
// 下载图片
saveFile (data, filename) {
let saveLink = document.createElementNS('http://www.w3.org/1999/xhtml', 'a')
saveLink.href = data
saveLink.download = filename
let event = document.createEvent('MouseEvents')
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
saveLink.dispatchEvent(event)
},
// 下载二维码
downloadCode () {
html2canvas(document.querySelector('#content'), {
allowTaint: true,
taintTest: false,
useCORS: true,
logging: true,
scale: 2.5
}).then(canvas => {
let image = document.createElement('img')
image.src = canvas.toDataURL('image/png')
this.saveFile(image.src, '')
}).catch((err) => {
console.log(err)
})
},
qrcodeScan (qrcodeUrl) {
QRCode.toDataURL(qrcodeUrl, {width: 180, height: 180}).then(url => {
this.newSrc = url
}).catch(err => {
console.error(err)
})
}
}
高德地图自带的,根据用户输入的地址,进行模糊搜索,用户进行选择定位
用vue
以及element-ui
实现的,
页面部分布局
<div class="location-wrap">
<div id="location"></div>
<div class="search">
<el-input
id="tip-input"
size="small"
class="search-input"
placeholder="请输入地址"
prefix-icon="el-icon-search"
v-model="address"
:clearable="true"
@input="mapLocation"
>
</el-input>
<ul class="list" v-show="searchMsg">
<li v-for="(item, index) in list" :key="index" @click="selectAddress(item)">{{item.name}}</li>
</ul>
</div>
</div>
js部分
在mounted时候,加载地图
<script>
import MP from '这个加载地图文件,访问也在简书中'
let map = '' // 定义地图
let marker = '' // 定义一个标记
export default {
data () {
return {
mapKey: '这是你的地图key',
address: '', // 输入地址
list: [], // 模糊搜索的list
searchMsg: false, // list下拉框的显示隐藏
lnglat: {} // 存储点击的经纬度
}
},
created () {
},
async mounted () {
await MP (this.mapKey)
this.map()
this.clickMap() // 地图上的点击事件
},
methods: {
// 将获取到的地址传回到父组件
handleChange (val) {
this.$emit('address', val)
},
// 下拉框中的选择
selectAddress (val) {
this.address = `${val.district}${val.name}`
this.handleChange(`${val.district}${val.name}`)
},
// 初始化地图
map () {
map = new AMap.Map('location', {
resizeEnable: true,
zoom: 14
})
},
// input事件
mapLocation () {
// 使用高德地图的自动补全和搜索的功能
map.plugin(['AMap.Autocomplete', 'AMap.PlaceSearch'], () => {
// 实例化Autocomplete
var autoOptions = {
city: '全国'
}
let autoComplete = new AMap.Autocomplete(autoOptions)
autoComplete.search(this.address, (status, result) => {
if (result && result.info === 'OK') {
this.list = result.tips
this.searchMsg = true
this.placeSearch(this.list.length && this.list[0].name)
}
})
})
},
placeSearch (value) {
let placeSearch = new AMap.PlaceSearch({
city: '全国',
map: map
})
placeSearch.search(value)
},
// 地图上的点击事件,根据点击位置,记一个mark,点击新的位置,去掉之前的mark,记录最新的
clickMap () {
map.on('click', (e) => {
if (JSON.stringify(this.lnglat) !== '{}') {
this.mark('remove', this.lnglat)
}
this.lnglat = e.lnglat
this.mark('add', e.lnglat)
map.plugin(['AMap.Geocoder'], () => {
let geocoder = new AMap.Geocoder({
radius: 1000,
extensions: 'all'
})
geocoder.getAddress([e.lnglat.lng, e.lnglat.lat], (status, result) => {
if (result && result.info === 'OK') {
this.address = `${result.regeocode.formattedAddress}`
this.handleChange(`${result.regeocode.formattedAddress}`)
this.close()
}
})
})
})
},
// 标记的新增和删除
mark (type, value) {
if (type === 'remove') {
return map.remove(marker)
}
marker = new AMap.Marker({
position: new AMap.LngLat(value.lng, value.lat),
title: '北京'
})
map.add(marker)
}
}
}
</script>
css样式,使用的less
.location-wrap {
position: relative;
width: 100%;
height: 500px;
}
#location {
width: 100%;
height: 100%;
}
.search {
position: absolute;
right: 10px;
top: 10px;
.el-input {
width: 400px;
}
.list {
width: 380px;
// height: 300px;
background: #ffffff;
padding: 0 10px;
color: #333;
font-size: 14px;
}
li {
line-height: 40px;
cursor: pointer;
}
}
提示:高德地图jsapi的地址
可以左右滑动的一个导航栏
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style type="text/css">
.app{
width: 100%;
overflow:hidden;
}
.app nav{
padding: 0 0.5rem;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: middle;
-ms-flex-align: middle;
align-items: middle;
overflow: auto;
}
.app p{
text-align: center;
font-size: 0.6rem;
-ms-flex-negative: 0;
flex-shrink: 0;
padding: 0.2rem;
margin: 5px;
}
.app p.active{
color: #ffffff;
background-color: #f00000;
}
</style>
</head>
<body>
<div class="app">
<nav>
<p v-for="(item,$index) in arr" @click="toggle($index)" :class="{active:$index==active}">{{item}}</p>
</nav>
</div>
<script>
var app=new Vue({
el:'.app',
data:{
active:0,
arr:[
"新闻1",
"新闻1",
"新闻1",
"新闻1",
"新闻1",
"新闻1",
"新闻1",
"新闻1",
"新闻1",
"新闻1",
"新闻1",
"新闻1"
]
},
computed:{
},
methods:{
toggle (index) {
this.active = index
}
},
})
</script>
<script type="text/javascript">
!function(e){function t(){var t=n.clientWidth,r="}";!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)&&t>1024&&(t=640,r=";max-width:"+t+"px;margin-right:auto!important;margin-left:auto!important;}"),e.rem=t/10,/ZTE U930_TD/.test(navigator.userAgent)&&(e.rem=1.13*e.rem),/Android\s+4\.4\.4;\s+M351\s/.test(navigator.userAgent)&&(e.rem=e.rem/1.05),/Android\s+5\.0\.1;\s+MX4\s/.test(navigator.userAgent)&&(e.rem=1.06382*e.rem),i.innerHTML="html{font-size:"+e.rem+"px!important;}body{font-size:"+12*(t/320)+"px"+r}var n=document.documentElement,i=document.createElement("style");n.firstElementChild.appendChild(i),e.addEventListener("resize",function(){t()},!1),e.addEventListener("pageshow",function(e){e.persisted&&t()},!1),t()}(window);
</script>
</body>
</html>
标题
[测试](www.baidu.com)
import wx from 'weixin-js-sdk'
// 首先要获取 微信的基本配置
wx.config({
// debug: true,
appId: res.appId,
timestamp: res.timeStamp, // 必填,生成签名的时间戳
nonceStr: res.nonceStr, // 必填,生成签名的随机串
signature: res.signature, // 必填,签名
jsApiList: ['openCard'] // 必填,需要使用的JS接口列表
})
wx.ready(function () {
wx.openCard({
cardList: data,
success: function () {
console.log('success')
},
fail: function () {
console.log('fail')
},
complete: function () {
console.log('complete')
},
cancel: function () {
console.log('cancel')
}
})
})
wx.error(function () {
console.log('err') // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
})
wx.config({
// debug: true,
beta: true,
appId: res.appId,
timestamp: res.timeStamp, // 必填,生成签名的时间戳
nonceStr: res.nonceStr, // 必填,生成签名的随机串
signature: res.signature, // 必填,签名
jsApiList: ['chooseInvoiceTitle'] // 必填,需要使用的JS接口列表
})
wx.ready(function () {
wx.invoke('chooseInvoiceTitle', {'scene': '1'}, function (res) {
})
})
wx.error(function (err) {
console.log(err)
})
Array.prototype.includes
includes是一个Array上很有用的方法,用于快速查找数组中是否包含某个元素,包括NaN(所以和indexOf不一样)
let arr = [1, 2, 3, NaN];
// 查找2是否存在于arr数组中
arr.includes(2) // true
// 第二个参数3表示数组下标为3的项,也即第4项开始查找
arr.includes(2, 3) // false
arr.includes(NaN) // true
arr.indexOf(NaN) != -1 // false
JavaScript也采用两个星符号**来表示Math.pow
let a = 2 ** 2;// 等同于: 2 * 2
let b = 2 ** 3;// 等同于: 2 * 2 * 2
// x **= y
let a = 2;
a **= 2;//等同于: a = a * a;
let b = 3;
b **= 3;//等同于: b = b * b * b;
用法是 Object.values(obj),obj 可以是一个对象或者数组
const obj = { x: 'xxx', y: 1 };
Object.values(obj); // ['xxx', 1]
const obj = ['e', 's', '8']; // 等同于 { 0: 'e', 1: 's', 2: '8' };
Object.values(obj); // ['e', 's', '8']
//当把数字当做对象的键的时候,返回的数组以键的值升序排序
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.values(obj); // ['yyy', 'zzz', 'xxx']
Object.values('es8'); // ['e', 's', '8']
Object.entries方法返回一个给定对象可枚举属性值的数组[key, value],与Object.values类似。
const obj = { x: 'xxx', y: 1 };
Object.entries(obj); // [['x', 'xxx'], ['y', 1]]
const obj = ['e', 's', '8'];
Object.entries(obj); // [['0', 'e'], ['1', 's'], ['2', '8']]
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.entries(obj); // [['1', 'yyy'], ['3', 'zzz'], ['10', 'xxx']]
Object.entries('es8'); // [['0', 'e'], ['1', 's'], ['2', '8']]
1、验证金额(输入整数,小数点后一或两位)
// 小数点后两位
export function CheckAmount (str) {
let reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/
return reg.test(str)
}
// 小数点后一位
export function CheckOnePoint (str) {
let reg = /(^[1-9]([0-9]+)?(\.[0-9]{1})?$)|(^(0){1}$)|(^[0-9]\.[0-9]?$)/
return reg.test(str)
}
2、验证身份证号
export function validateIDcard (str) {
const reg = /^[1-9][0-9]{5}([1][9][0-9]{2}|[2][0][0|1][0-9])([0][1-9]|[1][0|1|2])([0][1-9]|[1|2][0-9]|[3][0|1])[0-9]{3}([0-9]|[X])$/
return reg.test(str)
}
3、验证邮箱
export function CheckEmail(email){
return (/^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,8})$/.test(email))
}
4、手机号简单验证
export function CheckPhone(phone){
return (/^1[3|4|5|6|7|8|9]\d{9}$/.test(phone))
}
5、特殊字符和空格判断 如果有返回true
export function CheckString (str) {
let reg = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]")
let regSpace = /\s/g
return reg.test(str) || regSpace.test(str)
}
6、时间的一些转换
// 20180829105739 ====> 2018-08-29-10:57:39
export function changeTime (date) {
return `${date.slice(0, 4)}-${date.slice(4, 6)}-${date.slice(6, 8)} ${date.slice(8, 10)}:${date.slice(10, 12)}:${date.slice(12, 14)}`
}
// 20180829 ====> 2018-08-29
export function changeResponseDate (date = '') {
return `${date.slice(0, 4)}-${date.slice(4, 6)}-${date.slice(6, 8)}`
}
// 1546939193000 ===> 2019-01-08 17:19:53
export function formatTime (date) {
if (!date) {
return ''
}
date = new Date(date);
let day = date.getDate() > 9 ? date.getDate() : '0' + date.getDate()
let hour = date.getHours() > 9 ? date.getHours() : '0' + date.getHours()
let minute = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes()
let second = date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds()
let month = (date.getMonth() + 1) > 9 ? (date.getMonth() + 1) : '0' + (date.getMonth() + 1)
return `${date.getFullYear()}-${month}-${day} ${hour}:${minute}:${second}`
}
// 'Thu May 12 2017 08:00:00 GMT+0800 (**标准时间)' =>> yyyy-MM-dd hh:mm:ss
export function grpcDateFormat (date) {
if (!date) {
return ''
}
date = new Date(date);
let day = date.getDate() > 9 ? date.getDate() : '0' + date.getDate()
let hour = date.getHours() > 9 ? date.getHours() : '0' + date.getHours()
let minute = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes()
let second = date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds()
let month = (date.getMonth() + 1) > 9 ? (date.getMonth() + 1) : '0' + (date.getMonth() + 1)
return `${date.getFullYear()}-${month}-${day} ${hour}:${minute}:${second}`
}
npm install echarts mpvue-echarts --save
<template>
<view class="month-chart">
<view class="chart">
<mpvue-echarts canvasId="chartmonth" :echarts="echarts" @onInit="initChart" ref="chartmonth"/>
</view>
</view>
</template>
<script>
import * as echarts from 'echarts/echarts.min.js'
import mpvueEcharts from 'mpvue-echarts'
let chart = null
export default {
props: [],
components: {
mpvueEcharts
},
data () {
return {
echarts: echarts,
xAxisData: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'],
seriesS: [320, 302, 301, 334, 390, 330, 320],
seriesP: [120, 132, 101, 134, 90, 230, 210],
isNoMsg: false
}
},
created () {
},
mounted () {
},
methods: {
handleEchart (e) {
console.log(e)
},
initChart (e) {
let {
width,
height
} = e
let canvas = this.$refs.chartmonth.canvas
echarts.setCanvasCreator(() => canvas)
const chart = echarts.init(canvas, null, {
width: width,
height: height
})
canvas.setChart(chart)
let option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['合理化建议', '问题反映'],
itemGap: 30,
bottom: '20',
right: '20'
},
grid: {
left: '0',
top: '10',
containLabel: true
},
xAxis: {
type: 'category',
data: this.xAxisData,
axisTick: {
show: false
},
axisLine: {
show: false
}
},
yAxis: {
type: 'value',
// boundaryGap: [0, 0.01],
axisTick: {
show: false
},
axisLine: {
show: false
}
},
series: [
{
name: '合理化建议',
type: 'bar',
stack: '总量',
data: this.seriesS,
color: ['#44AEFF'],
barWidth: '10',
barGap: '0'
},
{
name: '问题反映',
type: 'bar',
stack: '总量',
data: this.seriesP,
color: ['#FF822E'],
barWidth: '10',
barGap: '0'
}
]
}
chart.setOption(option)
chart.on('click', this.handleEchart)
chart.on('legendselectchanged', params => {
chart.setOption({
legend: {
selected: { [params.name]: true}
}
})
})
this.$refs.chartmonth.setChart(chart)
}
}
}
</script>
<style lang="scss" scoped>
.month-chart {
padding: 10px 15px 0;
}
.chart {
width: 100%;
height: 320px;
}
</style>
停止微信开发者工具后重新运行,虽然显示图表,但是这不应该是正确的处理方式。
于是寻找另外一种解决办法。根据处理方法 #插件讨论# 【 ECharts页面模板 - DCloud 】APP中 报错 this.echarts.setCanvasCreator is not a function(https://ask.dcloud.net.cn/question/70370),
替换最新的 mpvue-echarts 组件echarts.vue, 源码地址:https://github.com/dcloudio/hello-uniapp/blob/master/components/mpvue-echarts/src/echarts.vue
替换后查看echarts.vue,可以看到init()通过$emit将onInit事件和数据发出
<mpvue-echarts ref="pieChart" :echarts="echarts" @onInit="initChart" />
methods:{
initChart:initChart
}
原因是外框的height为0,需要设置外框的高度。同时要注意page的css
page{display:flex;}会同样无法显示图表。
在小程序开发工具中编译和预览时,提示Error:源码包超出最大限制,source size 3905KB exceed max limit 2MB
参考:https://www.npmjs.com/package/mpvue-echarts
FAQ:打包结果超过小程序大小限制?
使用自定义版 echarts,官网定制
FAQ:文件太大怎么办?
本项目默认提供的 ECharts 文件是最新版本的包含所有组件文件,为了便于开发,提供的是未压缩的版本。远程调试或预览可以下载 echarts.min.js 压缩版本。
发布时,如果对文件大小要求更高,可以在 ECharts 在线定制网页下载仅包含必要组件的包,并且选择压缩。
定制按需选择后得到echarts.min.js
将echarts.min.js文件复制到echarts目录下。
import * as echarts from 'echarts/echarts.min.js'
import mpvueEcharts from 'mpvue-echarts/src/echarts.vue'
解决方法查看:UNI-app新引入echarts 报错 https://blog.csdn.net/qq_36444936/article/details/86599300
编辑刚才拷贝的echarts.min.js,检索“e(t.echarts={})”字符串
找到相邻的(this,function(t) 串 ,将其改为(this,function(t,window,document)保存即可
因为是适配小程序,所以一定要考虑代码量,chart.js使用在在线定制,在线定制地址:https://echarts.apache.org/zh/builder.html
**加粗的字体**
__加粗的字体__
eg:
加粗的字体 加粗的字体
*斜体的字体*
_斜体的字体_
eg:
斜体的字体 斜体的字体
***斜体加粗***
eg:
斜体加粗
~~加删除线的文体~~
eg:
加删除线的文体
>引用
eg:
引用
---
----
***
*****
![图片alt](图片地址 ''图片title'')
图片alt就是显示在图片下面的文字,相当于对图片内容的解释。
图片title是图片的标题,当鼠标移到图片上时显示的内容。title可加可不加
![blockchain](https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/
u=702257389,1274025419&fm=27&gp=0.jpg "区块链")
[超链接名](超链接地址 "超链接title")
title可加可不加
[百度](http://baidu.com)
eg: 百度
无序列表用 - + * 任何一种都可以
- 列表内容
+ 列表内容
* 列表内容
注意:- + * 跟内容之间都要有一个空格
eg:
有序列表 数字加点
1. 列表内容
2. 列表内容
3. 列表内容
注意:序号跟内容之间要有空格
eg:
上一级和下一级之间敲三个空格即可
- 列表内容
1. 列表内容
2. 列表内容
- 列表内容
- 列表内容
- 列表内容
eg:
表头|表头|表头
---|:--:|---:
内容|内容|内容
内容|内容|内容
第二行分割表头和内容。
- 有一个就行,为了对齐,多加了几个
文字默认居左
-两边加:表示文字居中
-右边加:表示文字居右
注:原生的语法两边都要用 | 包起来。此处省略
姓名|技能|排行
--|:--:|--:
刘备|哭|大哥
关羽|打|二哥
张飞|骂|三弟
姓名 | 技能 | 排行 |
---|---|---|
刘备 | 哭 | 大哥 |
关羽 | 打 | 二哥 |
张飞 | 骂 | 三弟 |
单行代码:代码之间分别用一个反引号包起来
`代码`
eg: 代码
代码块:代码之间分别用三个反引号包起来,且两边的反引号单独占一行
eg:
<script></script>
```flow
st=>start: 开始
op=>operation: My Operation
cond=>condition: Yes or No?
e=>end
st->op->cond
cond(yes)->e
cond(no)->op
&```
eg:
st=>start: 开始
op=>operation: My Operation
cond=>condition: Yes or No?
e=>end
st->op->cond
cond(yes)->e
cond(no)->op
&```
主要是用vue
安装mqtt npm i mqtt
import mqtt from 'mqtt'
let client = ''
export default {
created () {
let options = {
connectTimeout: 40000,
clientId: `id`,
username: `定义的用户名`,
password: `密码`,
path: '/mqtt',
clean: true,
useSSL: true/false,
port: '端口号',
topic: '通信'
}
client = mqtt.connect(`链接的地址`, options)
this.mqttMsg()
},
methods: {
mqttMsg () {
client.on('connect', () => {
client.subscribe(`通信`, { qos: 0 }, (error) => {
if (!error) {
console.log('success')
} else {
console.log('fail')
}
})
})
// 接收消息处理
client.on('message', (topic, message) => {
let msg = message.toString()
if (msg && JSON.parse(msg).content === 'ok') {
console.log('信息成功')
}
})
client.on('reconnect', (error) => {
console.log('正在重连:', error)
})
// 链接异常处理
client.on('error', (error) => {
console.log('连接失败:', error)
})
},
}
}
1.查询提示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>查询访问</title>
<style type="text/css">
*{margin:0px;padding: 0px;}
#container{width:800px;margin:auto;margin-top:10px;}
input[id="keywords"]{width: 500px;height: 40px;border:solid 2px #cecece;font-size: 22px;line-height: 40px;color:#888;padding-left: 10px;}
#sug{width:512px;list-style: none;border:solid 1px #ccc;}
#sug li{height: 30px;background:#fcfcfc;line-height:30px;font-size:18px}
</style>
<script type="text/javascript" src="../jquery-1.12.4.js"></script>
</head>
<body>
<div id="container">
<div>
<input type="text" id="keywords" placeholder="请输入关键词">
</div>
<ul id="sug">
<!-- <li>建议搜索的关键词</li> -->
</ul>
</div>
<script>
// 获取输入框
var $kw = $("#keywords");
// 添加键盘按键抬起事件
$kw.keyup(function(){
// 获取输入框中的输入
var $value = $kw.val();
// 调用函数,获取数据
$.ajax({
url:"https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?cb=?",
type:"get",
data:{wd:$value},
dataType:"jsonp",
success:function(msg){
// 当url接口访问成功的时候,自动调用success对应的函数,接口返回的数据会自动存放在函数的参数data中
console.log(msg.s);
// 将输入输出到页面中;dom操作
var _sug = msg.s;
// 清空原来的url标签;
$("#sug").empty();
for (var i = 0;i< _sug.length;i++){
// 创建一个li标签
var $li = $("<li>")
// 标签中添加文本数据
$li.text(_sug[i]);
// 将li标签,添加到页面中
$("#sug").append($li);
}
}
});
});
</script>
</body>
</html>
<!-- dataType:"jsonp",
同源策略:web规范了只有相同源头(域名)的数据才可以互相访问
同源策略是为了数据的安全性,而设置的一种网络数据访问限制
跨域:从不同的域名下访问指定的数据 -->
2.天气预报查询地址
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>天气预报</title>
<style>
*{margin:0px;padding:0px;}
#container{width:800px;margin:auto;font-size: 20px;font-weight: bolder;}
input[id="city"]{width:500px;height:35px;border:solid 2px #cecece;font-size:22px;line-height:35px;color:#888;padding-left:10px; margin:10px;}
#show{display:block;width: 600px;height: 300px;border: solid 2px #888;margin: 10px auto; list-style: none;padding: 10px;border-radius: 8px;box-shadow: 10px 10px 5px #888}
</style>
<script type="text/javascript" src="../jquery-1.12.4.js"></script>
</head>
<body>
<div id="container">
<div>
请输入城市名称:
<input type="text" id="city" placeholder="请输入想查询的地区">
</div>
<ul id="show">
<li>天气信息</li>
</ul>
</div>
<script>
// 获取需要的标签对象
var _city = $("#city");
var _show = $("#show");
// 添加事件处理
_city.blur(function(){
// 获取输入框中的输入数据
var $value = _city.val();
_show.empty();
// 调用函数,获取数据
$.ajax({
url:"http://wthrcdn.etouch.cn/weather_mini?callback=?",
type:"get",
data:{city:$value},
dataType:"jsonp",
success:function(msg){
// 当url接口访问成功的时候,自动调用success对应的函数,接口返回的数据会自动存放在函数的参数data中
console.log(msg);
// 获取城市数据,展示到页面中
var $city = $("<li>");
$city.text(msg.data.city + "天气预报信息:");
// 获取今天温度数据
var $wd = $("<li>");
$wd.text("今天温度:"+ msg.data.wendu);
// 获取今天感冒指数数据
var $gm = $("<li>");
$gm.text("温馨提示:"+ msg.data.ganmao);
// 今天天气预报
var $today = $("<li>");
var $date = $("<span>").text("日期:" + msg.data.forecast[0].date)
var $type = $("<span>").text(";今天天气:" + msg.data.forecast[0].type)
var $high = $("<span>").text(";最高气温:" + msg.data.forecast[0].high)
var $low = $("<span>").text(";最低气温:" + msg.data.forecast[0].low)
var $fl = $("<span>").text(";风力:" + msg.data.forecast[0].fengli)
var $fx = $("<span>").text(";风向:" + msg.data.forecast[0].fengxiang)
$today.append($date).append($type).append($high).append($low).append($fl).append($fx);
_show.append($city).append($wd).append($gm).append($today);
},
error:function(){
console.log("运行错误...");
}
});
});
</script>
</body>
</html>
3.快递单号查询接口
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>快递信息查询</title>
<style type="text/css">
*{margin: 0;padding: 0;}
#container{width: 800px;margin: 15px auto;font-size: 20px;font-weight: bolder;}
select[id="company"]{width: 200px;height: 30px;font-size: 18px;font-family: "微软雅黑";border-radius: 5px;}
#wb{float: left;}
input[id="postid"]{margin:10px auto;width: 200px;height: 20px;font-size: 14px;font-family: "微软雅黑";border-radius: 3px;}
button[id="cx"]{display: block;width: 56px;height: 26px;background-color:#388bff;color:white;margin: 8px 380px;}
ul[id="show"]{list-style: none;width: 500px;height:500px;border:solid 2px #888; border-radius: 8px; }
#container ul li p{padding:15px;width:480px;
min-height: 50px;font-size:14px;}
</style>
<script type="text/javascript" src="../jquery-1.12.4.js">
</script>
</head>
<body>
<div id="container">
<div>
<label for="company">快递公司名称</label>
<select id="company" name="address">
<option value="shunfeng">顺丰速运</option>
<option value="shentong">申通快递</option>
<option value="ems">EMS</option>
<option value="yuantong">圆通速递</option>
<option value="zhongtong">中通快递</option>
<option value="tiantian">天天快递</option>
<option value="huitongkuaidi">汇通快递</option>
<option value="yunda">韵达速递</option>
<option value="quanfengkuaidi">全峰快递</option>
<option value="debangwuliu">德邦</option>
<option value="zhaijisong">宅急送</option>
</select>
</div>
<div id="wb">
<label for="post">输入快递单号</label>
<input type="text" id="postid">
</div>
<div>
<button id="cx">查询</button>
</div>
<ul id="show">
<li>
<i></i>
<p>物流信息</p>
</li>
</ul>
<div style="clear:both;"></div>
</div>
<script>
// 获取标签对象:快递公司
var $selector=$("#company");
// 获取快递单号
var $postid=$("#postid");
// 查询
var $cx=$("#cx");
// 给查询按钮添加点击事件
$cx.click(function(){
// 获取需要的数据
var $company = $selector.val();
var $value = $postid.val();
// ajax 获取数据
$.ajax({
url:"https://sp0.baidu.com/9_Q4sjW91Qh3otqbppnN2DJv/pae/channel/data/asyncqury?cb=?",
type:"get",
data:{com:$company,nu:$value,appid:4001},
dataType:"json",
success:function(msg){
// 清空历史消息
$("#show").empty();
// 获取接口返回的数据
console.log(msg);
var $info = msg.data.info.context;
// 循环遍历数据
for(var i = 0; i <$info.length;i++){
// 获取每一笔的时间信息
var $time = $info[i].time;
$time = getTimeStr($time);
// 获取每一笔的快递信息
var $desc = $info[i].desc;
// 创建标签,添加到页面中
var $msg = $("<p>").text($time + ":" + $desc);
var $i = $("<i>");
var $kd = $("<li>");
$kd.append($i).append($msg);
// 添加到页面中
$("#show").append($kd);
}
},
error:function(){
console.log("系统繁忙,查询失败");
}
});
});
// 获取时间字符串
function getTimeStr(dt){
var _date = new Date(parseInt(dt*1000));
return _date.getFullYear() + "-" + (_date.getMonth() + 1) + "-" + _date.getDate() + " " + _date.getHours() + ":" + _date.getMinutes() + ":" + _date.getSeconds();
}
</script>
</body>
</html>
安装
使用
js防抖和节流属于性能优化的知识,实际遇到的频率比较高,处理不当或者放任不管就容易造成浏览器卡死
防抖,顾名思义,防止抖动,以免把一次事件误认为多次,敲键盘就是一个每天都会接触到的防抖操作。
想要了解一个概念,必先了解概念所应用的场景。在 JS 这个世界中,有哪些防抖的场景呢
代码如下,可以看出来防抖重在清零 clearTimeout(timer)
function debounce (f, wait) {
let timer
return (...args) => {
clearTimeout(timer)
timer = setTimeout(() => {
f(...args)
}, wait)
}
}
节流,顾名思义,控制水的流量。控制事件发生的频率,如控制为1s发生一次,甚至1分钟发生一次。与服务端(server)及网关(gateway)控制的限流 (Rate Limit) 类似。
代码如下,可以看出来节流重在加锁 timer=timeout
function throttle (f, wait) {
let timer
return (...args) => {
if (timer) { return }
timer = setTimeout(() => {
f(...args)
timer = null
}, wait)
}
}
clearTimeout
防抖可以比作等电梯,只要有一个人进来,就需要再等一会儿。业务场景有避免登录按钮多次点击的重复提交timer=timeout
timer = null
节流可以比作过红绿灯,每等一个红灯时间就可以过一批。A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.