首页
统计
赞助
留言
关于
更多
友链
壁纸
直播
Search
1
Joe — 一款个人类型Typecho主题
33,527 阅读
2
Joe开源目录程序系统
12,325 阅读
3
Typecho自定义后台编辑器功能
8,533 阅读
4
Joe主题实现自动更新
7,705 阅读
5
Joe主题自定义搭配色教程
4,578 阅读
WEB前端
CSS
React
Vue 2.0
Vue 3.0
JavaScript
TypeScript
Typecho
小程序
苹果CMS
其他
生活
登录
Search
https://78.al
累计撰写
76
篇文章
累计收到
3,785
条评论
首页
栏目
WEB前端
CSS
React
Vue 2.0
Vue 3.0
JavaScript
TypeScript
Typecho
小程序
苹果CMS
其他
生活
页面
统计
赞助
留言
关于
友链
壁纸
直播
搜索到
76
篇与
HaoOuBa
的结果
迭代器
我们都知道可以用 for...of... 来循环可迭代对象,例如循环 数组、字符串、Map、Set等,然后看这样一个例子例子使用 for...of... 来循环数组和对象,看是什么结果let arr = [1, 2, 3] let obj = { a: 1, b: 2, c: 3 } for(let val of arr) { console.log(val) } for(let val of obj) { console.log(val) }接着运行上面的代码,会出现以下报错信息:可以看到,数组正常循环没有问题,但是到了obj,会报:obj is not iterable(obj不是一个可迭代对象、obj不可被迭代)这是为什么呢?将arr和obj分别使用 console.dir() 进行打印查看let arr = [1, 2, 3] let obj = { a: 1, b: 2, c: 3 } console.dir(arr) console.dir(obj)可以看到,arr的原型上挂载着一个 Symbol[Symbol.iterator],而obj的原型上并没有这个属性,因此这就是为什么obj不可以被迭代的原因但是如果非得让obj也成为一个 可迭代对象,如何去实现呢?此时就需要给obj身上加上一个迭代器let arr = [1, 2, 3] let obj = { a: 1, b: 2, c: 3 } obj[Symbol.iterator] = function () { /* 必须得return 一个对象出去 */ return { /* 这是固定写法 */ next() { /* next也需要return一个对象出去 */ return { value: '1', // value 当前迭代出去的值 done: true // 如果为true,表示迭代结束,false表示迭代没结束 } } } } for (let item of obj) { console.log(item) }运行上方的代码,会发现控制台不显示任何内容,也就是 for...of... 并没有循环,这是为什么呢?因为next里面直接return出去了一个done为true的值,表示迭代结束,此时迭代直接结束,就没有了循环,因此将上方代码改造如下:let arr = [1, 2, 3] let obj = { a: 1, b: 2, c: 3 } obj[Symbol.iterator] = function () { let values = Object.values(obj) let index = 0 /* 必须得return 一个对象出去 */ return { /* 这是固定写法 */ next() { if (index >= values.length) { return { done: true // 此时迭代结束,就不需要再return value出去 } } else { return { value: values[index++], done: false } } } } } for (let item of obj) { console.log(item) }运行上方的代码,此时obj已经可以使用 for...of... 进行循环,并且此时的obj已经是一个可迭代对象接着不使用上方的 for...of... 进行迭代,使用手动进行迭代,分析这个步骤let arr = [1, 2, 3] let obj = { a: 1, b: 2, c: 3 } obj[Symbol.iterator] = function () { let values = Object.values(obj) let index = 0 /* 必须得return 一个对象出去 */ return { /* 这是固定写法 */ next() { if (index >= values.length) { return { done: true // 此时迭代结束,就不需要再return value出去 } } else { return { value: values[index++], done: false } } } } } let values = obj[Symbol.iterator]() console.log(values) // 得到迭代器对象,里面含有next方法 console.log(values.next()) // done:false(表示可以继续迭代),并且value为1 console.log(values.next()) // done:false(表示可以继续迭代),并且value为2 console.log(values.next()) // done:false(表示可以继续迭代),并且value为3 console.log(values.next()) // done:true(表示迭代结束)接下来就是迭代相关的专业话语看完上面的原理,再来看迭代器相关的话语1、迭代协议:规定迭代与实现的逻辑(也就是上面迭代器里的逻辑)2、迭代器:具体的迭代实现逻辑(也就是上面的迭代器函数)3、迭代对象:可被迭代的对象,已经实现[Symbol.iterator]方法的对象(就是上面加了迭代器后的obj)
2021年02月24日
737 阅读
2 评论
8 点赞
2021-02-24
JS封装下载blob类型文件的函数
export const downloadFile = (blob, fileName) => { let a = document.createElement('a'); a.href = window.URL.createObjectURL(blob); a.download = fileName; a.click(); };
2021年02月24日
635 阅读
3 评论
6 点赞
2021-02-23
JS正则限制只能输入数字、或带小数点的数字,并且小数后面限制多少位
length 代表如果输入含小数位的时候,小数位的个数const length = 2 const reg = new RegExp(`^\\d+(\\.\\d{1,${length}})?$`)
2021年02月23日
656 阅读
2 评论
3 点赞
2021-02-22
Object.defineProperty与Proxy的使用
这个方法的主要用处是用来做数据劫持的,在vue2.x主要使用这个方法,在3.0中换成了proxy做数据劫持,数据劫持就是监听到数据的变化,然后可以做什么等Object.defineProperty/* 随便定义一个对象 */ let obj = { name: 'hello', age: 18, child: { sex: '女' } } observer(obj) function observer(obj) { /* 判断传入进来的是否是对象 */ if (obj.constructor === Object) { /* 循环对象 */ for (let key in obj) { /* 如果值不是对象,则做劫持 */ if (obj[key].constructor !== Object) { /* 定义一个临时变量,用于return出去 */ let _value = obj[key] Object.defineProperty(obj, key, { /* 设置属性可以被删除,可以被修改 */ configurable: true, /* 设置属性可以被遍历 */ enumerable: true, get() { console.log('触发读取') return _value }, set(newVal) { console.log('触发修改') _value = newVal } }) } else { /* 否则进行递归,再次判断 */ observer(obj[key]) } } } }Proxylet obj = { name: '小红', age: 1 } obj = new Proxy(obj, { get(target, key) { console.log(target) console.log(key) }, set(target, key, newVal) { console.log(target) console.log(key) console.log(newVal) } }) console.log(obj)
2021年02月22日
268 阅读
2 评论
3 点赞
2021-02-21
简单的模拟Vue替换插值表达式的功能
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> {{ msg }}111{{ msg }} <div>{{msg}}</div> </div> <script> class Vue { constructor(options) { this.options = options /* 初始化编译dom */ this.compile() } compile() { let el = document.querySelector(this.options.el) if (!el) return console.warn('element not exist!') let childNodes = el.childNodes /* 递归编译节点 */ childNodes.length && this.compileNodes(childNodes) } compileNodes(childNodes) { /* 循环节点 */ childNodes.forEach(node => { /* 如果是文本节点,则进行替换插值表达式 */ if (node.nodeType === 3) { let reg = /\{\{\s*([^\{\{\}\}\s]+)\s*\}\}/g if (reg.test(node.textContent)) { /* $1就是插值表达式里面的属性值 */ let $1 = RegExp.$1 node.textContent = node.textContent.replace(reg, this.options.data[$1]) } } else { /* 如果不是文本节点,则进行递归,并且有子节点 */ node.childNodes.length && this.compileNodes(node.childNodes) } }) } } new Vue({ el: '#app', data: { msg: '测试数据' } }) </script> </body> </html>
2021年02月21日
265 阅读
0 评论
3 点赞
2021-02-20
自行封装一个深拷贝的函数
在实际项目中,经常使用到深拷贝,索性封装成一个函数function deepCopy(obj) { // 1、为了兼容数组和对象,所以写一个兼容性赋值 let newObj = Array.isArray(obj) ? [] : {} // 2、接下来进行循环传进来的对象 (for...in...也会循环原型链上的内容) for(let key in obj) { // 3、因为for...in会循环原型链上的内容,而我们深拷贝的新对象无需原型链上的内容,因此加一层原型链判断 if(obj.hasOwnProperty(key)) { // 判断是非原型上的数据 // 4、接着判断是复杂数据类型,还是基本数据类型,如果是基本数据类型,直接赋值就行 if(typeof(obj[key]) !== 'object') { // 基本数据类型 newObj[key] = obj[key] } else { // 复杂数据类型,递归再次进行判断 newObj[key] = deepCopy(obj[key]) } } } return newObj } // 接着验证上面函数 let obj = { name: 'lis', fn: () => { console.log(1) }, child: { age: 1, son: [] } } let newObj = deepCopy(obj) console.log(newObj)
2021年02月20日
305 阅读
2 评论
8 点赞
2021-02-20
为你的网站添加点击散开特效
将以下代码复制到你网站最底部即可实现<canvas id="fireworks" style="position: fixed; left: 0px; top: 0px; pointer-events: none; z-index: 2147483647; width: 1920px; height: 151px;" width="3840" height="302"></canvas> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/animejs@3.0.1/lib/anime.min.js"></script> <script type="text/javascript"> function updateCoords(e) { pointerX = (e.clientX || e.touches[0].clientX) - canvasEl.getBoundingClientRect().left, pointerY = e.clientY || e.touches[0].clientY - canvasEl.getBoundingClientRect().top } function setParticuleDirection(e) { var t = anime.random(0, 360) * Math.PI / 180, a = anime.random(50, 180), n = [-1, 1][anime.random(0, 1)] * a; return { x: e.x + n * Math.cos(t), y: e.y + n * Math.sin(t) } } function createParticule(e, t) { var a = {}; return a.x = e, a.y = t, a.color = colors[anime.random(0, colors.length - 1)], a.radius = anime.random(16, 32), a.endPos = setParticuleDirection(a), a.draw = function() { ctx.beginPath(), ctx.arc(a.x, a.y, a.radius, 0, 2 * Math.PI, !0), ctx.fillStyle = a.color, ctx.fill() }, a } function createCircle(e, t) { var a = {}; return a.x = e, a.y = t, a.color = "#F00", a.radius = .1, a.alpha = .5, a.lineWidth = 6, a.draw = function() { ctx.globalAlpha = a.alpha, ctx.beginPath(), ctx.arc(a.x, a.y, a.radius, 0, 2 * Math.PI, !0), ctx.lineWidth = a.lineWidth, ctx.strokeStyle = a.color, ctx.stroke(), ctx.globalAlpha = 1 }, a } function renderParticule(e) { for (var t = 0; t < e.animatables.length; t++) e.animatables[t].target.draw() } function animateParticules(e, t) { for (var a = createCircle(e, t), n = [], i = 0; i < numberOfParticules; i++) n.push(createParticule(e, t)); anime.timeline().add({ targets: n, x: function(e) { return e.endPos.x }, y: function(e) { return e.endPos.y }, radius: .1, duration: anime.random(1200, 1800), easing: "easeOutExpo", update: renderParticule }).add({ targets: a, radius: anime.random(80, 160), lineWidth: 0, alpha: { value: 0, easing: "linear", duration: anime.random(600, 800) }, duration: anime.random(1200, 1800), easing: "easeOutExpo", update: renderParticule, offset: 0 }) } function debounce(fn, delay) { var timer return function() { var context = this var args = arguments clearTimeout(timer) timer = setTimeout(function() { fn.apply(context, args) }, delay) } } var canvasEl = document.querySelector("#fireworks"); if (canvasEl) { var ctx = canvasEl.getContext("2d"), numberOfParticules = 30, pointerX = 0, pointerY = 0, tap = "mousedown", colors = ["#FF1461", "#18FF92", "#5A87FF", "#FBF38C"], setCanvasSize = debounce(function() { canvasEl.width = 2 * window.innerWidth, canvasEl.height = 2 * window.innerHeight, canvasEl.style.width = window.innerWidth + "px", canvasEl.style.height = window.innerHeight + "px", canvasEl.getContext("2d").scale(2, 2) }, 500), render = anime({ duration: 1 / 0, update: function() { ctx.clearRect(0, 0, canvasEl.width, canvasEl.height) } }); document.addEventListener(tap, function(e) { "sidebar" !== e.target.id && "toggle-sidebar" !== e.target.id && "A" !== e.target.nodeName && "IMG" !== e.target.nodeName && (render.play(), updateCoords(e), animateParticules(pointerX, pointerY)) }, !1), setCanvasSize(), window.addEventListener("resize", setCanvasSize, !1) } </script>
2021年02月20日
1,311 阅读
7 评论
22 点赞
2021-02-20
Vue中解决对象内存地址一致的几种方案
在开发vue项目中,经常会遇到内存地址一样的问题,导致修改这里,另一处同时发生改变解决方案:1、利用JSON方法(极其不推荐,会丢失属性,例如函数、undefined)let obj = {} let newObj = JSON.parse(JSON.stringify(obj))2、深拷贝3、利用Object.assig方法export default { data() { return { test: {} } }, methods: { change(obj) { this.test = Object.assign({}, obj) } } }4、利用对象展开运算符let obj1 = { a: 1, b: 2 } let obj2 = {...obj1}
2021年02月20日
204 阅读
0 评论
2 点赞
2021-02-20
JS封装获取文件大小的函数
封装的函数function formatBytes(bytes, decimals = 2) { if (bytes === 0) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + sizes[i]; }使用方法formatBytes(file.size, decimals = 2)
2021年02月20日
244 阅读
0 评论
3 点赞
2021-02-20
Vue中this.$options.data() 重置data里的数据
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <button @click="btnClick">click</button> <button @click="btnReset">reset</button> <p><input type="text" v-model="message"></p> <p>{{message}}</p> </div> <script src="./vue.js"></script> <script> let vm = new Vue({ el: "#app", data() { return { message: '' } }, methods: { btnClick() { this.message = 'bbbbbbbbbb' }, btnReset() { Object.assign(this.$data, this.$options.data.call(this)) } }, }) </script> </body> </html>
2021年02月20日
306 阅读
0 评论
3 点赞
2021-02-20
-webkit-box-orient属性编译时被删除时的解决办法
例如打包编译如下scss代码时,会将-webkit-box-orient属性删除掉display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis;解决办法,在该属性的前后加上防编译注释display: -webkit-box; -webkit-line-clamp: 3; /*! autoprefixer: off */ -webkit-box-orient: vertical; /* autoprefixer: on */ overflow: hidden; text-overflow: ellipsis;
2021年02月20日
477 阅读
0 评论
2 点赞
2021-02-20
Vue解决路由重复点击报错的问题
router.js文件// 加上这个 const originalPush = Router.prototype.push; Router.prototype.push = function push(location) { return originalPush.call(this, location).catch(err => err) }
2021年02月20日
264 阅读
0 评论
2 点赞
1
...
4
5
6
7