首页
友链
壁纸
留言
今日热榜
更多
关于
时光
推荐
精品流量卡
Search
1
都二十多年了,你的梦为什么还没碎!
57,085 阅读
2
2022年5个好用的 BT/ 磁力链接下载工具推荐 |Windows 、安卓系统
37,328 阅读
3
nps内网穿透实现外网访问树莓派
32,418 阅读
4
实践利用宝塔建emlog个人博客-超详细【原创】
26,129 阅读
5
Typecho-Joe-Theme主题帮助文档
24,602 阅读
闲杂乱码
Python
网站源码
微信小程序
娱乐分享
Is相册
软件工具
登录
Search
标签搜索
PHP
HTML
API
Javascript
源码
JS
Vue
Github
CloudFlare
接口
函数
SQL
ASP.NET
MVC
EF
T4模板
后台管理
CDN
微信小程序
MAC
韩小韩
累计撰写
261
篇文章
累计收到
1,303
条评论
首页
栏目
闲杂乱码
Python
网站源码
微信小程序
娱乐分享
Is相册
软件工具
页面
友链
壁纸
留言
今日热榜
关于
时光
推荐
精品流量卡
搜索到
151
篇与
闲杂乱码
的结果
2023-03-06
class中函数的this指向
定义一个基础的类class Person { constructor(name = '杜恒') { this.name = name } speak() { console.log(this); } }将上面的类实例出一个对象p,并调用p的speak方法const p = new Person() p.speak() // Person {name: "杜恒"}{callout color="#f0ad4e"}上面的打印结果显示由类构造出的实例对象,因此this会指向由类构造出的实例对象{/callout}尝试将p实例对象身上的speak方法赋值给另一个变量进行调用const test = p.speak test() // undefined打印undefind,因此上面的方法可以改写成如下const test = function () { "use strict" console.log(this); } test() // undefined{callout color="#ef4db4"}由此可以得出,在class中,定义的方法,class会默认在函数体内开启严格模式,严格控制this的指向{/callout}
2023年03月06日
2,906 阅读
0 评论
1 点赞
2023-02-26
Vue底层判断标签的性能优化方法
在vue中,如果写div、span等正常的html标签,vue会解析成传统的html标签,但当写不是这些标签的时候,vue会认为他是一个组件,例如:<Custom></Custom>。是如何做到这种判断的呢,首先自己来实现一个这样的判断const tags = 'div,span,img,a'.split(",") function checkTag(tag) { return tags.some(item => item === tag) } console.log(checkTag('Custom')); // false console.log(checkTag('div')); // true console.log(checkTag('a')); // true这里的实现方案有很多,可以用for、some、forEach等,但是都是离不开循环,思考这样的一个问题,传入一个a,a在字符串最后一个位置,所以会循环4次来判断是否包含a,如果页面上的标签极多,甚至会有上万次的循环再来查看Vue实现这个的方式,大致源码如下const tags = 'div,span,img,a' function makeMap(str) { var map = Object.create(null); var list = str.split(','); for (var i = 0; i < list.length; i++) { map[list[i]] = true; } return function (val) { return map[val]; } } const isHtmlTag = makeMap(tags) isHtmlTag('div') isHtmlTag('Custom') isHtmlTag('a')这里可以看出,实现出一个柯里化函数,并且也是一个闭包状态。此时,在第一次调用时,会循环一次,后续不论在去判断什么标签,都不会再去循环,因为第一次的循环结果利用闭包已经存在了内存里,这就是闭包能带来的性能优化
2023年02月26日
2,479 阅读
0 评论
1 点赞
2023-02-18
Vue.set与this.$set源码
Vue.set()和this.$set()应用的场景在 Vue 2.X 项目开发中,有时候需要对数组进行修改,或是对对象新增一个属性,但是发现页面并不会同步更新。例如:const vm = new Vue({ data: { arr: [1, 2], obj: { a: 3 } } }); vm.$data.arr[0] = 3; // 页面不会发生改变 vm.$data.obj.b = 3; // 页面不会发生改变此时就需要使用到 Vue.set() 或 this.$set()。这个2个的使用方法一样,不过一个是挂载在Vue身上,一个挂载在Vue.prototype上// Vue.set import { set } from '../observer/index' Vue.set = set // this.$set import { set } from '../observer/index' Vue.prototype.$set = se使用Vue.set或this.$set来实现页面不更新的问题:const vm = new Vue({ data: { arr: [1, 2], obj: { a: 3 } } }); // 修改数组 Vue.set(vm.$data.arr, 0, 3); vm.$set(vm.$data.arr, 0, 3); // 对象新增属性 Vue.set(vm.$data.obj, 'b', 3); vm.$set(vm.$data.obj, 'b', 3);set函数的源代码../observer/indexfunction set (target: Array<any> | Object, key: any, val: any): any { // isUndef(target):用于判断传入的target是否是undefined或null // isPrimitive(target):用于判断传入的target是否是原始数据类型 // 如果是 null 或者是 undefined 时,抛出异常 if (process.env.NODE_ENV !== 'production' &&(isUndef(target) || isPrimitive(target))) { warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`) } // 如果传入了一个数组,并且传入的key是数组的有效值 if (Array.isArray(target) && isValidArrayIndex(key)) { // 用于设置数组的最大length // Math.max(target.length, key):取数组的length和key二者中的最大值 target.length = Math.max(target.length, key) // 直接调用数组身上的splice方法,因为Vue里变异了数组方法,调用会触发dep.notify() target.splice(key, 1, val) return val } // 接下来就是对象的判断了 // 如果传入的 key 在原对象中,说明已经是响应式了,直接修改即可 if (key in target && !(key in Object.prototype)) { target[key] = val return val } // 这里到最后的代码,都是对象不在原对象上,是新增的属性值 const ob = (target: any).__ob__ // 如果是Vue实例对象,或根数据对象,则抛出警告 if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV !== 'production' && warn( 'Avoid adding reactive properties to a Vue instance or its root $data ' + 'at runtime - declare it upfront in the data option.' ) return val } // 如果没有 __ob__ 表示当前 target 不是响应式的,那么直接赋值 if (!ob) { target[key] = val return val } // 剩下就是给响应式对象增加一个 key 新属性,并通知更新 defineReactive(ob.value, key, val) ob.dep.notify() return val }
2023年02月18日
2,261 阅读
0 评论
0 点赞
2023-02-03
Vue 2与Vue 3在自定义组件v-model上的区别
{callout color="#f0ad4e"}在vue开发中,通常会对一个自定义的组件进行封装,并实现v-model双向绑定功能{/callout}在 Vue 2 中,通常这样实现父组件<template> <Child v-model="number"></Child> </template> <script> export default { data() { return { number: 0 } }, components: { Child: () => import("./Child.vue") } } </script>子组件<template> <button @click="handleClick">{{ value }}</button> </template> <script> export default { props: { value: Number }, methods: { handleClick() { // 通过emit一个input事件出去,实现 v-model this.$emit('input', this.value + 1) } } } </script>在 vue 3 中,通过这样实现父组件<template> <Child v-model="number"></Child> </template> <script lang="ts"> import { defineComponent, ref } from 'vue'; export default defineComponent({ setup() { const number = ref(0); return { number }; }, }); </script>子组件<template> <button @click="handleClick">{{ value }}</button> </template> <script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ props: { // 更换成了 modelValue modelValue: Number }, setup(props, { emit }) { // 关闭弹出层 const handleClick = () => emit('update:modelValue', props.modelValue + 1); return { handleClick }; }, }); </script>
2023年02月03日
2,477 阅读
0 评论
1 点赞
2023-01-27
Linux系统下使用iftop结合iptables服务解决带宽被恶意请求的问题
{callout color="#f0ad4e"}最近博客总时不时的打不开,或者是打开巨慢。打开宝塔面板,发现能登录,但是登录非常缓慢,最后挤进来后,看到流量可视化图,上行一直流量一直居高不下。服务器带宽是2兆的,上行200kb,说明直接将整个服务器带宽占满,导致服务器无法访问{/callout}排查Linux下使用iftop工具结合iptables服务来解决带宽资源被恶意请求满的问题,主要通过2个步骤来实现使用iftop 工具查出来是哪些个IP地址在请求主机的带宽资源,找出耗带宽的元凶找出耗带宽的IP地址或者段,分析是out方向还是in方向,使用iptables规则来进行控制首先安装 iftop 工具yum install flex byacc libpcap ncurses ncurses-devel libpcap-devel接着输入 iftop -n 运行,运行后会出现以下界面左侧表示自己的服务器的内网ip中间的<= =>这两个左右箭头,表示的是流量的方向右侧表示请求或发送的ip最右侧表示流量信息从上面图中可以看到,排行第一的流量消耗最大,并且是右箭头。反映出本地内网ip正朝着62.210.177.44这个ip疯狂发送数据,导致服务器带宽占满,无法访问,知道这个ip后,就可以利用 iptables 屏蔽这个ip禁止某个IP访问服务器iptables -I INPUT -s 地址 -j DROP禁止服务器访问此IPiptables -A OUTPUT -d 地址 -j DROP上面图中主要流量是从out方向出去的,那就直接在OUT方向设置策略iptables -A OUTPUT -d 62.210.177.44 -j DROP屏蔽掉后,在看流量统计已经恢复到了正常状态相关参数说明iptables相关参数:禁止此IP访问服务器:iptables -I INPUT -s 1.2.3.4 -j DROP iptables -A INPUT -s 1.2.3.4 -j DROP禁止服务器访问此IP:iptables -A OUTPUT -d 1.2.3.4 -j DROP如果要封某个网段:iptables -I INPUT -s 1.2.3.0/24 -j DROP清空屏蔽IP:iptables -t filter -D INPUT -s 1.2.3.4 -j DROP iptables -t filter -D OUTPUT -d 1.2.3.4 -j DROP一键清空所有规则:iptables -F查看:iptables -L INPUT iptables -L处理IP碎片数量,防止攻击,允许每秒100:iptables -A FORWARD -f -m limit --limit 100/s --limit-burst 100 -j ACCEPT设置ICMP包过滤,允许每秒1个包,限制触发条件是10个包:iptables -A FORWARD -p icmp -m limit --limit 1/s --limit-burst 10 -j ACCEPT
2023年01月27日
786 阅读
0 评论
0 点赞
2023-01-08
记录部分安卓手机 input type="file"的onchange不能触发问题
今天写了一个文件上传,发现在部分安卓手机上触发不了onchange事件,代码如下:<input type="file" id="input" /> <script> // 在部分安卓手机不触发 input.onchange = () => { alert(123) } </script>经过不断测试后发现,在标签上补上accept="image/*"后可解决该问题,修复后的代码如下:<input type="file" accept="image/*" id="input" /> <script> input.onchange = () => { alert(123) } </script>
2023年01月08日
600 阅读
0 评论
0 点赞
2022-12-26
JS压缩图片并保留图片元信息
{callout color="#f0ad4e"}JS实现图片压缩比较简单,但是图片经过压缩后,压缩后的图片的元信息(拍摄时间、设备、地点)等会丢失掉,如果在特殊场景中需要使用这些元信息的话,就会出现问题了,因此需要将未压缩前的图片元信息填充至压缩后的图片中,以下是实现代码{/callout}// 封装一个获取变量的数据类型函数 const getType = (data: unknown): string => { const toStingResult = Object.prototype.toString.call(data); const type = toStingResult.replace(/^\[object (\w+)\]$/, "$1"); return type.toLowerCase(); }; // 封装一个将 Base64 的字符串转换成 Blob 流的函数 const dataURLtoBlob = (dataURL: string): Blob | null => { const dataType = getType(dataURL); if (dataType !== "string") return null; const arr = dataURL.split(","); if (!arr[0] || !arr[1]) return null; const code = window.atob(arr[1]); const mimeExpRes = arr[0].match(/:(.*?);/); if (!mimeExpRes) return null; let len = code.length; const mime = mimeExpRes[1]; if (!mime) return null; const ia = new Uint8Array(len); while (len--) ia[len] = code.charCodeAt(len); return new Blob([ia], { type: mime }); }; // 利用规律编码格式把里面的标记以及值等分割开来,传原图片的 ArrayBuffer 进来 const getSegments = (arrayBuffer: ArrayBuffer): number[][] => { if (!arrayBuffer.byteLength) return []; let head = 0; let length, endPoint, seg; const segments = []; const arr = [].slice.call(new Uint8Array(arrayBuffer), 0); while (1) { if (arr[head] === 0xff && arr[head + 1] === 0xda) break; if (arr[head] === 0xff && arr[head + 1] === 0xd8) { head += 2; } else { length = arr[head + 2] * 256 + arr[head + 3]; endPoint = head + length + 2; seg = arr.slice(head, endPoint); head = endPoint; segments.push(seg); } if (head > arr.length) break; } return segments; }; // 传入上面 getSegments 的返回值,取出EXIF图片元信息 const getEXIF = (segments: number[][]): Array<number> => { if (!segments.length) return []; let seg: Array<number> = []; for (let i = 0; i < segments.length; i++) { const item = segments[i]; if (item[0] === 0xff && item[1] === 0xe1) { seg = seg.concat(item); } } return seg; }; // 将 getEXIF 获取的元信息,插入到压缩后的图片的 Blob 中,传 压缩图片后的 Blob 流 const insertEXIF = (blob: Blob, exif: number[]): Promise<Blob> => { return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = () => { const arr = [].slice.call(new Uint8Array(fileReader.result as ArrayBuffer), 0); if (arr[2] !== 0xff || arr[3] !== 0xe0) { return reject(new Error("Couldn't find APP0 marker from blob data")); } const length = arr[4] * 256 + arr[5]; const newImage = [0xff, 0xd8].concat(exif, arr.slice(4 + length)); const uint8Array = new Uint8Array(newImage); const newBlob = new Blob([uint8Array], { type: "image/jpeg" }); resolve(newBlob); }; fileReader.readAsArrayBuffer(blob); }); }; // 压缩图片逻辑 const compressImage = (file: File, quality: number): Promise<Blob | null> => { return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = () => { const img = new Image(); img.src = fileReader.result as string; img.onload = () => { const { width, height } = img; const canvas = window.document.createElement("canvas"); const ctx = <CanvasRenderingContext2D>canvas.getContext("2d"); canvas.width = width; canvas.height = height; ctx.drawImage(img, 0, 0, width, height); const fileData = canvas.toDataURL("image/jpeg", quality); const fileBlob = dataURLtoBlob(fileData); resolve(fileBlob); }; img.onerror = (err) => reject(err); }; fileReader.onerror = (err) => reject(err); fileReader.readAsDataURL(file); }); }; /** * @description: 完整的压缩图片,最终对外暴露的函数 * @param {File} file * @param {number} quality 0 - 1 * @return {Promise<File>} */ export default (file: File, quality = 0.5): Promise<File> => { return new Promise((resolve, reject) => { const dataType = getType(file); if (dataType !== "file") return reject(new Error(`Expected parameter type is file, You passed in ${dataType}`)); if (file.type.indexOf("image") === -1) return resolve(file); // 压缩图片 compressImage(file, quality) .then((compressdBlob) => { if (!compressdBlob) return resolve(file); const fileReader = new FileReader(); fileReader.onload = () => { // 获取图片元信息 const segments = getSegments(fileReader.result as ArrayBuffer); const exif = getEXIF(segments); // 没有元数据的时候, 直接抛出压缩后的图片 if (!exif.length) return resolve(new File([compressdBlob], file.name, { type: file.type, lastModified: file.lastModified })); // 有元数据的时候, 将元信息合并到压缩图片里 insertEXIF(compressdBlob, exif) .then((newBlob) => resolve(new File([newBlob], file.name, { type: file.type, lastModified: file.lastModified }))) .catch(() => resolve(file)); }; fileReader.onerror = () => resolve(file); fileReader.readAsArrayBuffer(file); }) .catch(() => resolve(file)); }); };
2022年12月26日
1,408 阅读
0 评论
0 点赞
2022-12-06
今日热榜HotList-Web前端开源Vue - (聚合热榜)
{message type="info" content="每日热榜前端配合后端(韩小韩聚合热榜API)一起使用,后端源接口为官方接口。"/}环境需求Nodejs >14.1.0使用框架VueElement-UI页面AND源码截图{gird column="2" gap="15"}{gird-item} {/gird-item}{gird-item}{/gird-item}{/gird}源码地址{cloud title="HotList-Web" type="github" url="https://github.com/uxiaohan/HotList-Web" password=""/}{callout color="#f0ad4e"}后端配合 韩小韩API 聚合热榜API 使用.或者自建API使用.源码自行编译 或 直接上传 dist文件夹内已编译文件.{/callout}成品演示{abtn icon="fa-link" color="#ff6800" href="https://hot.vvhan.com/" radius="" content="今日热榜 HotList-Web"/} {abtn icon="fa-link" color="#00d5ff" href="https://api.vvhan.com/hotlist.html" radius="" content="韩小韩API 聚合热榜API"/}希望给个 Star 😬
2022年12月06日
1,269 阅读
2 评论
8 点赞
1
2
3
...
19