HTTPS页面里动态的引入HTTP资源,比如引入一个js文件,会被直接block掉的.在HTTPS页面里通过AJAX的方式请求HTTP资源,也会被直接block掉的。 Mixed Content: The page at 'xxx' was loaded over HTTPS, but requested an insecure resource 'xxx'. This request has been blocked; the content must be served over HTTPS. 解决办法: 页面的head中加入: <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> 意思是自动将http的不安全请求升级为https from:https://www.cnblogs.com/cici1989/p/11229810.html
View Details一.问题背景 一个二维平面上有一群NPC,每一回合可以随机向上/下/左/右任一方向走1步,有单位碰撞体积(NPC位置不能重合) 规则就这么简单,初始情况下这群NPC是被人工均匀分布在二维平面上的,运行N个回合后发现所有NPC都集中在了左下角。。怎么会这样,说好的随机呢? 二.分析 现有的实现是这样的: 根据NPC的当前位置判断得到可以去的位置,把结果存放在一维数组arr里P.S.上/下/左/右最多4个点(周围空荡荡的),最少0个点(被围起来了) 生成[0, arr.length – 1]内的一个随机数,作为目标位置索引值index
1 2 3 4 5 |
// 生成随机数[min, max] w.Util.rand = function(min, max) { return Math.round(Math.random() * (max - min) + min); } |
控制NPC移动到arr[index]的位置 逻辑应该是没有问题的,可是为什么运行结果是NPC都跑到左下角开会去了呢?等等,为什么是左下而不是其它角角? 因为实现第一步的时候是按照上 -> 下 -> 左 -> 右的顺序判断的,最后都去了左下角,说明向上和向右的概率太小了(生成随机数的函数rand是没问题的,确实能得到[min, max]的数) 问题的根源是Math.random()不给力,生成[0, 1)之间的小数,取到0和靠近1的值概率很小,所以rand()函数生成的随机数取到min和mix的概率也很小,向上/向右的可能性也就小了 三.解决方案 既然取到min和max的概率很小,中间概率比较均匀,那好办,切掉这两个值就好了。具体实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function randEx(min, max) { var num; var maxEx = max + 2; // 扩大范围到[min, max + 2],引入两个多余值替换min/max do{ num = Math.round(Math.random() * (maxEx - min) + min); num--; } while (num < min || num > max); // 范围不对,继续循环 return num; } |
值得一提的是上面的加2减1比较巧妙,能够恰好排除min和max 四.运行结果 JS中Math.random()返回值的概率差异可能比你想象的要大些,在实际应用中是不可接受的 测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
// 生成随机数[min, max] w.Util.rand = function(min, max) { return Math.round(Math.random() * (max - min) + min); } // 生成更随机的随机数[min, max] function randEx(min, max) { var num; var maxEx = max + 2; // 扩大范围到[min, max + 2],引入两个多余值替换min/max do{ num = Math.round(Math.random() * (maxEx - min) + min); num--; } while (num < min || num > max); // 范围不对,继续循环 return num; } function testRand(times, fun) { var arr = [1, 2, 3, 4]; var count = []; var randVal; for (var i = 0; i < times; i++) { // 获取[0, 3]的随机数 randVal = fun(0, arr.length - 1); // 记录次数 if (typeof count[randVal] !== "number") { count[randVal] = 0; } count[randVal]++; } console.log(count); } console.log("100 times"); testRand(100, w.Util.rand); // 之前的实现 testRand(100, randEx); // 改进过的实现 console.log("1000 times"); testRand(1000, w.Util.rand); // 之前的实现 testRand(1000, randEx); // 改进过的实现 console.log("10000 times"); testRand(10000, w.Util.rand); // 之前的实现 testRand(10000, randEx); // 改进过的实现 console.log("100000 times"); testRand(100000, w.Util.rand); // 之前的实现 testRand(100000, randEx); // 改进过的实现 |
后话 理论上Java的Math.random(),C#的next可能也存在这个问题,这里就没有必要验证了,因为randEx函数的思想(加2减1,嫌效果不好还可以加4减2、加6减3……直到满意为止)是通用的 from:https://www.cnblogs.com/ayqy/p/4511565.html?utm_source=tuicool
View Details更多文章请戳VSCode插件开发全攻略系列目录导航。 发布方式 插件开发完了,如何发布出去分享给他人呢?主要有3种方法: 方法一:直接把文件夹发给别人,让别人找到vscode的插件存放目录并放进去,然后重启vscode,一般不推荐; 方法二:打包成vsix插件,然后发送给别人安装,如果你的插件涉及机密不方便发布到应用市场,可以尝试采用这种方式; 方法三:注册开发者账号,发布到官网应用市场,这个发布和npm一样是不需要审核的。 本地打包 无论是本地打包还是发布到应用市场都需要借助vsce这个工具。 安装:
1 2 |
npm i vsce -g |
打包成vsix文件:
1 2 |
vsce package |
打包的时候如果没有设置repository会有提示,所以最好设置一下。 生成好的vsix文件不能直接拖入安装,只能从扩展的右上角选择Install from VSIX安装: 发布应用市场 Visual Studio Code的应用市场基于微软自己的Azure DevOps,插件的身份验证、托管和管理都是在这里。 要发布到应用市场首先得有应用市场的publisher账号; 而要有发布账号首先得有Azure DevOps组织; 而创建组织之前,首先得创建Azure账号; 创建Azure账号首先得有Microsoft账号; 是不是有点晕,梳理一下: 一个Microsoft账号可以创建多个Azure组织; 一个组织可以创建多个publisher账号; 同时一个组织可以创建多个PAT(Personal Access Token,个人访问令牌); 3.1. 注册账号 首先访问 https://login.live.com/ 登录你的Microsoft账号,没有的先注册一个: 然后访问: https://aka.ms/SignupAzureDevOps ,如果你从来没有使用过Azure,那么会看到如下提示: 点击继续,默认会创建一个以邮箱前缀为名的组织。 3.2. 创建令牌 默认进入组织的主页后,点击右上角的Security: 点击创建新的个人访问令牌,这里特别要注意Organization要选择all accessible organizations,Scopes要选择Full access,否则后面发布会失败。 创建令牌成功后你需要本地记下来,因为网站是不会帮你保存的。 3.3. 创建发布账号 获得个人访问令牌后,使用vsce以下命令创建新的发布者:
1 2 |
vsce create-publisher your-publisher-name |
your-publisher-name必须是字母数字下划线,这是全网唯一的账号,然后会依次要求输入昵称、邮箱、令牌: 创建成功后会默认登录这个账号,接下来你可以直接发布了,当然,如果你是在其它地方创建的,可以试用vsce login your-publisher-name来登录。 除了用命令之外,你还可以使用网页版创建发布账号:https://marketplace.visualstudio.com/manage 3.4. 发布 发布很简单:
1 2 |
vsce publish |
发布成功后大概需要过几分钟才能在应用市场搜到。过几分钟就可以访问网页版的插件主页:https://marketplace.visualstudio.com/items?itemName=sxei.vscode-plugin-demo vscode里面也能搜到了: 3.4.1. 发布注意事项 README.md文件默认会显示在插件主页; README.md中的资源必须全部是HTTPS的,如果是HTTP会发布失败; CHANGELOG.md会显示在变更选项卡; 如果代码是放在git仓库并且设置了repository字段,发布前必须先提交git,否则会提示Git working directory not clean; 另外,如前面所说,如果Organization没有选择all accessible organizations,或者Scopes没有选择Full access,发布的时候可能会报如下错误:
1 2 3 4 |
Error: Failed Request: Unauthorized(401) - https://marketplace.visualstudio.com/_apis/gallery Be sure to use a Personal Access Token <span class="hljs-built_in">which</span> has access to **all accessible accounts**. See https://code.visualstudio.com/docs/tools/vscecli<span class="hljs-comment">#_common-questions for more information.</span> |
3.4.2. 增量发布 版本号:major.minor.patch 如果想让发布之后版本号的patch自增,例如:1.0.2 -> 1.0.3,可以这样:
1 2 |
vsce publish patch |
执行这个命令后会自动修改package.json里面的版本号。同理,vsce publish minor也是可以的。 3.5. 取消发布
1 2 |
vsce unpublish (publisher name).(extension name) |
3.6. 更新 如果修改了插件代码想要重新发布,只需要修改版本号然后重新执行vsce publish即可。 插件升级 4.1. 发布到了应用市场 如果发布到了应用市场,那么一般来说会自动检测有没有新版本,有的话会自动无感知升级,但具体什么时候会去检测我还没有研究过,已经确定的是在扩展面板搜索插件名字会自动检测,重启vscode也会检测。 4.2. 如果是本地打包 如果是打包成vsix,那么只能自己实现升级检测功能呢,通过对比服务器上某个文件的版本号,具体我就不细讲了。 […]
View Details文章索引 VSCode插件开发全攻略(一)概览 VSCode插件开发全攻略(二)HelloWord VSCode插件开发全攻略(三)package.json详解 VSCode插件开发全攻略(四)命令、菜单、快捷键 VSCode插件开发全攻略(五)跳转到定义、自动补全、悬停提示 VSCode插件开发全攻略(六)开发调试技巧 VSCode插件开发全攻略(七)WebView VSCode插件开发全攻略(八)代码片段、设置、自定义欢迎页 VSCode插件开发全攻略(九)常用API总结 VSCode插件开发全攻略(十)打包、发布、升级 本系列文章同步首发于多个平台,限于精力有限,后续如有更新和修改,仅更新我的个人博客上的内容,欢迎戳这里查看最新版:http://blog.haoji.me/vscode-plugin-overview.html 写在前面 一年前我写了一篇3万多字的Chrome插件(扩展)开发全攻略,反响还不错,帮助了很多新手快速上手,甚至包括大名鼎鼎的红芯浏览器(戳这里了解更多)。 最近因工作需要又接触到了vscode插件开发,所以趁势再写一篇有关vscode插件开发的文章,记录一些自己踩过的坑以及接触vscode插件开发这2个多月以来的心得体会,让大家少走一些弯路避免重复踩坑。 目前网上有关介绍vscode插件开发的文章也有挺多的,但都不够深入,基本上都是点到为止,篇幅不大,本系列文章争取多讲一些,涵盖面会更广,干货更多。 鉴于之前写过几篇内容较多的文章大家都反馈说阅读麻烦,一篇文章内容太多看起来太累,所以这次就拆分来写。 关于vscode插件 相信大家对vscode应该都不陌生,VSCode是微软出的一款轻量级代码编辑器,免费而且功能强大,以功能强大、提示友好、不错的性能和颜值俘获了大量开发者的青睐,对JavaScript和NodeJS的支持非常好,自带很多功能,例如代码格式化,代码智能提示补全、Emmet插件等。 再强大的IDE那也不可能面面俱到什么功能都塞进去,那样只会导致IDE本身太臃肿。功能嘛,按需索取,所以,vscode的很多强大功能都是基于插件实现的,IDE只提供一个最基本的框子和最基本功能,由插件来丰富和扩展它的功能。 vscode插件可以很轻松的在应用商店搜索并下载到,应用商店官网是:https://marketplace.visualstudio.com/vscode ,vscode推出时间本身并不长,但生态发展得非常好,应用商店已经有各种各样丰富的插件供大家使用了。 因为vscode本身都是用浏览器实现的,所以其插件不用说肯定也是基于HTML+JS等前端技术实现,从形式上看就是一个类似于npm包的vsix文件,只不过按照一些特殊规范来实现一些特殊功能,所以vscode插件开发难度不大,甚至可以说熟悉了相关API之后很容易。 有必要学习vscode插件开发吗 有!而且非常有必要!每个人都会多多少少有一些自己的特殊定制需求,当你不知道开发一个IDE插件其实也很容易、或者你没有意识到通过开发插件可以帮你提升多大效率时,你并不会下意识的将一些问题的解决方式往IDE插件开发上去想。至少我曾经就是这样的,提升开发效率大部分时候想到的都是写一些脚本工具、写一些浏览器插件、写一些客户端工具等,接触到IDE插件开发之后发现原来有些问题可以通过更高效的方式来解决,毕竟IDE才是我们程序员每天接触最多的东西。 但至于可以开发什么样的插件、实现什么样的功能、以什么样的形式呈现,这就要靠你从工作和生活中去发现、去找灵感并提炼了。 demo下载 本系列文章所有demo均在这个仓库里:https://github.com/sxei/vscode-plugin-demo ,可以直接下载运行。当然还有更简单的,这个demo已经发布到应用市场了,大家可以直接点击这里下载安装,或则您也可以直接在vscode里面搜索plugin-Demo就能搜到: vscode插件能做什么 既然前面讲到学习vscode插件开发很有必要,那插件到底能做什么呢?能实现什么功能?能从哪些方面动手脚?下面我们就来列举一些好让大家有个大概了解。 6.1. 不受限的本地磁盘访问 因为vscode是基于Electron开发的,可以使用nodejs随意读写本地文件、跨域请求、甚至创建一个本地server,这都是没有任何限制的,所以只要你想做,基本上没有不能实现的。 6.2. 自定义命令、快捷键、菜单 vscode插件很多功能都是基于一个个命令实现的,我们可以自定义一些命令,这个命令将出现在按下Ctrl+Shift+P后的命令列表里面,同时可以给命令配置快捷键、配置资源管理器菜单、编辑器菜单、标题菜单、下拉菜单、右上角图标等。 6.3. 自定义跳转、自动补全、悬浮提示 自定义跳转: 自动补全: 提示: 6.4. 自定义设置、自定义欢迎页 6.5. 自定义WebView 6.6. 自定义左侧功能面板 6.7. 自定义颜色、图标主题 6.8. 新增语言支持 给某一种原有没有的语言提供语言支持,语言支持包括很多方面,比如代码高亮、语法解析、折叠、跳转、补全等; 6.9. Markdown增强 你可以自定义markdown预览的样式、添加一些新语法、新功能的支持。 6.10. 其它 其它还有比如状态栏修改、通知提示、编辑器控制、git源代码控制、任务定义、Language Server、Debug Adapter等等。 收尾 本文作为开篇,不做太多详细介绍,只是为了让大家对vscode插件有一个大致了解,后面再分篇慢慢细讲。 参考资料 微软VSCode插件开发官方文档:https://code.visualstudio.com/docs/extensions/overview from:https://www.cnblogs.com/liuxianan/p/vscode-plugin-overview.html
View Details1、通过instanceof判断 instanceof运算符用于检验构造函数的prototype属性是否出现在对象的原型链中的任何位置,返回一个布尔值。
1 2 3 4 |
let a = []; a instanceof Array; //true let b = {}; b instanceof Array; //false |
在上方代码中,instanceof运算符检测Array.prototype属性是否存在于变量a的原型链上,显然a是一个数组,拥有Array.prototype属性,所以为true。 需要注意的是,prototype属性是可以修改的,所以并不是最初判断为true就一定永远为真。 其次,当我们的脚本拥有多个全局环境,例如html中拥有多个iframe对象,instanceof的验证结果可能不会符合预期,例如:
1 2 3 4 5 6 7 8 |
//为body创建并添加一个iframe对象 var iframe = document.createElement('iframe'); document.body.appendChild(iframe); //取得iframe对象的构造数组方法 xArray = window.frames[0].Array; //通过构造函数获取一个实例 var arr = new xArray(1,2,3); arr instanceof Array;//false |
导致这种问题是因为iframe会产生新的全局环境,它也会拥有自己的Array.prototype属性,让不同环境下的属性相同很明显是不安全的做法,所以Array.prototype !== window.frames[0].Array.prototype,想要arr instanceof Array为true,你得保证arr是由原始Array构造函数创建时才可行。 2、通过constructor判断 我们知道,实例的构造函数属性constructor指向构造函数,那么通过constructor属性也可以判断是否为一个数组。
1 2 |
let a = [1,3,4]; a.constructor === Array;//true |
同样,这种判断也会存在多个全局环境的问题,导致的问题与instanceof相同。 3、通过Object.prototype.toString.call()判断 Object.prototype.toString().call()可以获取到对象的不同类型,多个全局环境也适用
1 2 3 4 5 6 7 8 9 |
// 检验是否是数组 let a = [1,2,3] Object.prototype.toString.call(a) === '[object Array]';//true //检验是否是函数 let b = function () {}; Object.prototype.toString.call(b) === '[object Function]';//true //检验是否是数字 let c = 1; Object.prototype.toString.call(c) === '[object Number]';//true |
4、通过Array.isArray()判断 简单好用,而且对于多全局环境,Array.isArray() 同样能准确判断,但有个问题,Array.isArray() 是在ES5中提出,也就是说在ES5之前可能会存在不支持此方法的情况。
1 2 |
let a = [1,2,3] Array.isArray(a);//true |
最终推荐方法
1 2 3 4 5 |
if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; } |
from:https://www.cnblogs.com/chenmeijiao/p/12060845.html
View DetailsVue中的nextTick涉及到Vue中DOM的异步更新,感觉很有意思,特意了解了一下。其中关于nextTick的源码涉及到不少知识,很多不太理解,暂且根据自己的一些感悟介绍下nextTick。 一、示例 先来一个示例了解下关于Vue中的DOM更新以及nextTick的作用。 模板
1 2 3 4 5 6 7 8 9 |
<div class="app"> <div ref="msgDiv">{{msg}}</div> <div v-if="msg1">Message got outside $nextTick: {{msg1}}</div> <div v-if="msg2">Message got inside $nextTick: {{msg2}}</div> <div v-if="msg3">Message got outside $nextTick: {{msg3}}</div> <button @click="changeMsg"> Change the Message </button> </div> |
Vue实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
new Vue({ el: '.app', data: { msg: 'Hello Vue.', msg1: '', msg2: '', msg3: '' }, methods: { changeMsg() { this.msg = "Hello world." this.msg1 = this.$refs.msgDiv.innerHTML this.$nextTick(() => { this.msg2 = this.$refs.msgDiv.innerHTML }) this.msg3 = this.$refs.msgDiv.innerHTML } } }) |
点击前 点击后 从图中可以得知:msg1和msg3显示的内容还是变换之前的,而msg2显示的内容是变换之后的。其根本原因是因为Vue中DOM更新是异步的(详细解释在后面)。 二、应用场景 下面了解下nextTick的主要应用的场景及原因。 在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中 在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted()钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。 具体原因在Vue的官方文档中详细解释: Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的 Promise.then 和MessageChannel,如果执行环境不支持,会采用 setTimeout(fn, 0)代替。 例如,当你设置vm.someData = 'new value’,该组件不会立即重新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新。多数情况我们不需要关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。 三、nextTick源码浅析 作用 Vue.nextTick用于延迟执行一段代码,它接受2个参数(回调函数和执行回调函数的上下文环境),如果没有提供回调函数,那么将返回promise对象。 源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
/** * Defer a task to execute it asynchronously. */ export const nextTick = (function () { const callbacks = [] let pending = false let timerFunc function nextTickHandler () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } } // the nextTick behavior leverages the microtask queue, which can be accessed // via either native Promise.then or MutationObserver. // MutationObserver has wider support, however it is seriously bugged in // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It // completely stops working after triggering a few times... so, if native // Promise is available, we will use it: /* istanbul ignore if */ if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => { p.then(nextTickHandler).catch(logError) // in problematic UIWebViews, Promise.then doesn't completely break, but // it can get stuck in a weird state where callbacks are pushed into the // microtask queue but the queue isn't being flushed, until the browser // needs to do some other work, e.g. handle a timer. Therefore we can // "force" the microtask queue to be flushed by adding an empty timer. if (isIOS) setTimeout(noop) } } else if (!isIE && typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]' )) { // use MutationObserver where native Promise is not available, // e.g. PhantomJS, iOS7, Android 4.4 var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = document.createTextNode(String(counter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } } else { // fallback to setTimeout /* istanbul ignore next */ timerFunc = () => { setTimeout(nextTickHandler, 0) } } return function queueNextTick (cb?: Function, ctx?: Object) { let _resolve callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { _resolve = resolve }) } } })() |
首先,先了解nextTick中定义的三个重要变量。 callbacks 用来存储所有需要执行的回调函数 pending 用来标志是否正在执行回调函数 timerFunc 用来触发执行回调函数 接下来,了解nextTickHandler()函数。
1 2 3 4 5 6 7 8 |
function nextTickHandler () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } } |
这个函数用来执行callbacks里存储的所有回调函数。 接下来是将触发方式赋值给timerFunc。 先判断是否原生支持promise,如果支持,则利用promise来触发执行回调函数; 否则,如果支持MutationObserver,则实例化一个观察者对象,观察文本节点发生变化时,触发执行所有回调函数。 如果都不支持,则利用setTimeout设置延时为0。 最后是queueNextTick函数。因为nextTick是一个即时函数,所以queueNextTick函数是返回的函数,接受用户传入的参数,用来往callbacks里存入回调函数。 上图是整个执行流程,关键在于timeFunc(),该函数起到延迟执行的作用。从上面的介绍,可以得知timeFunc()一共有三种实现方式。 Promise MutationObserver setTimeout 其中Promise和setTimeout很好理解,是一个异步任务,会在同步任务以及更新DOM的异步任务之后回调具体函数。 下面着重介绍一下MutationObserver。 MutationObserver是HTML5中的新API,是个用来监视DOM变动的接口。他能监听一个DOM对象上发生的子节点删除、属性修改、文本内容修改等等。 调用过程很简单,但是有点不太寻常:你需要先给他绑回调:
1 |
var mo = new MutationObserver(callback) |
通过给MutationObserver的构造函数传入一个回调,能得到一个MutationObserver实例,这个回调就会在MutationObserver实例监听到变动时触发。 这个时候你只是给MutationObserver实例绑定好了回调,他具体监听哪个DOM、监听节点删除还是监听属性修改,还没有设置。而调用他的observer方法就可以完成这一步:
1 2 3 4 |
var domTarget = 你想要监听的dom节点 mo.observe(domTarget, { characterData: true //说明监听文本内容的修改。 }) |
[…]
View Details现在遇到一个需求要删掉下标为index的元素,下面介绍两种方法: 一、splice:删除后,后面的元素自动填补到前面 arr.splice(index, 1) 举例:现在有数组 arr=['a',’b',’c',’d'] arr.splice(1, 1); //结果arr=['a',’c',’d'](下标1开始,删除1个) 注意: 上面的代码中,我们要注意,如果想修改 arr 的值,直接这样操作 arr 直接就变了,而不要写作 arr= arr.splice(1,1),因为 splice() 方法的返回值为删除掉的元素。 补充: spice增加: arr.splice(1,0,’str'); //结果arr=['a',’str',’b',’c',’d'] spice替换: arr.splice(1,1,’str'); //结果arr=['a',’str',’c',’d'] spice替换2: arr.splice(1,2,’str'); //结果arr=['a',’str',’d'](就是说:下标1开始2个换成1个“str”) spice删除多个: arr.splice(1,2); //结果arr=['a',’d'] 二、delete:删除后,该下标位置元素为undefined deletearr[index];//结果arr=['a',undefined,’c',’d'] from:https://www.cnblogs.com/belongs-to-qinghua/p/12393296.html
View Details实现功能:使用富文本编辑器编写文章,然后把编写成功的文章用子组件显示。 问题描述:父组件给子组件传递数据,子组件第一次调用数据的时候页面渲染是正常的,当数据变化的时候,子组件的页面渲染就失效了。 问题判断:通过一次次测试发现,第一次打开子组件的时候页面的渲染是正常的,后面打开之后渲染就失效了。所以初步怀疑是第二次调用组件的时候没有对数据进行渲染。 解决方案一: 当数据变更后,通过watch 监听,先去销毁当前的组件,然后再重现渲染。使用 v-if 可以解决这个问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<template> <third-comp v-if="reFresh"/> </template> <script> export default{ data(){ return { reFresh:true, menuTree:[] } }, watch:{ menuTree(){ this.reFresh= false this.$nextTick(()=>{ this.reFresh = true }) } } } </script> |
解决方案二: 通过vue key 实现,原理官方文档。所以当key 值变更时,会自动的重新渲染。(推荐)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<template> <third-comp :message="menuData" :key="menuKey"/> </template> <script> export default{ data(){ return { menuKey:1, menuData: "", } }, watch:{ menuData(){ ++this.menuKey } } } </script> |
from:https://www.cnblogs.com/zyulike/p/12036456.html
View Details1. find()与findIndex() find()方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。 [1, 2, 5, -1, 9].find((n) => n < 0) //找出数组中第一个小于 0 的成员 // -1 find()方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。 findIndex()方法的用法与find()方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。 [1, 2, 5, -1, 9].findIndex((n) => n < 0) //返回符合条件的值的位置(索引) // 3 2. filter() filter()方法使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组。 filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或 等价于 true 的值 的元素创建一个新数组。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。filter 不会改变原数组。 var arr = [10, 20, 30, 40, 50] var newArr = arr.filter(item => item > 30); console.log(newArr); //[40, 50] //数组去重 var arr = [1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 0, 8, 6, 3, […]
View Details数组与字符串相互转换方法
toString() 将数组转换成一个字符串
toLocalString() 把数组转换成本地约定的字符串
join() 将数组元素连接起来以构建一个字符串