1220-客户端检测

如今的浏览器虽然接口已大致统一,但是每家浏览器难免都有自己的“想法”,于是会出现个别的不统一,这些差异迫使Web开发者自己去设计兼容这些差异,客户端检测就是最常见的检测手段,通过检测结果来进一步克服和避免这些缺陷。 客户端检测可大致分为三种:能力检测,用户代理检测,软件与硬件检测。 能力检测 能力检测也成为特性检测,因为不同浏览器提供的接口不是完全相同,于是可以通过简单的逻辑判断来检测在该浏览器环境下能否调用特定API,同时还能间接判断出浏览器类型。 比如,在IE5之前没有document.getElementById这个DOM方法,但是可以通过document.all来实现相同的功能。于是,可以进行如下的能力检测。 const getElementById = (id) => { if(document.getElementById){ return document.getElementById(id) } else if (document.all){ return document.all[id] } else { throw new Error('该浏览不支持任何通过ID获取DOM元素的方法') } } 需要注意的是,实现能力检测是一定要落实到具体的功能上,即某个能力的存在并不能代表其他能力也存在。 function getWindowWidth() { if (document.all) { // 假设 IE return document.documentElement.clientWidth; // 不正确的用法! } else { return window.innerWidth; } } 比如上述例子,document.all的存在并不能说明documentElement.clientWidth的存在。其实这段代码的本意是通过document.all来判断当前浏览器是不是IE浏览器,事实document.all的存在并不能一定确认该浏览器就是IE浏览器。 基于能力检测进行浏览器分析 除了上述可以进行基本的功能检测以外,还可以通过能力检测来进行浏览器的特性支持检测,比如是否支持Netscape插件,是否具有DOM Level 1能力等等。 // 红宝书P384 // 检测浏览器是否支持 Netscape 式的插件 let hasNSPlugins = !!(navigator.plugins && navigator.plugins.length); // 检测浏览器是否具有 DOM Level 1 能力 let hasDOM1 = !...

December 20, 2021 · 2 min · 276 words · Runtus

设计模式 - 观察者模式 - 发布订阅模式

观察者模式和发布订阅模式是平常业务开发中最常见的设计模式,虽然网上大多数文章将二者归为一类,其实不然,它们两者之间还是有细微的差距。 先来个观察者模式的定义 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的某个属性(或状态)发生变化时,会通知所有观察者对象,让它们自动更新。 现实映射 举一个🌰,高中的时候,我会经常去问老师问题,有时候遇到比较难的问题,老师一时半会解不开,老师会说**“你先去做其他的事情吧,一会儿我找到解题思路了来叫你”**。于是乎我先去做其他事情,等待老师的召唤。过了一会儿,老师叫另一个同学来叫我去办公室找他,于是我马上放下手中的活,冲向的老师的办公室…… 在这里例子里,我是一位观察者,而老师则是一位我观察的对象,当老师的状态发生了变化(指想出了题的思路),我就会接受到对应的信息,然后马上更新我自己的状态(指润去找老师)。 来点转换 上述例子如果在发布-订阅模式里,我则摇身一变,变成了订阅者,专门订阅老师发布的通知信息,而老师则作为了发布者。 其实,上述例子还不能完全展示出定义所说的一对多关系,因为订阅者只有我一个人,但其实稍微扩展一下,变成多位同学向老师询问同一道题目,那这就是标准的观察者模式了,多位观察者“观察”老师的状态。 来点代码 通过上述的定义和描述,大概可以知道,在观察者模式中,一共有两个类:发布者类和订阅者类。作为一个发布者,很容易可以想到它有下面几个基本方法:增加订阅者,通知订阅者,移除订阅者。思路有了,下面就直接实现。 // 发布者类 class Publisher { constructor() { this.observers = [] // Observer -> 观察员 } // 添加订阅者 add(observers) { this.observers.push(...observers) } // 移除订阅者 remove(observer) { this.observers.forEach((item, index) => { if (item === observer) { this.observer.splice(index, 1) } }) } // 通知订阅者 notify() { this.observers.forEach((item) => { item.update(); // 注意,订阅者的方法应该它们本身定义的 }) } } 发布者基本类设计完毕,下面开始设计下订阅者,其实订阅者很简单,它最核心的就一个方法:收到发布者的信息后,去进行状态更新。如下所示。 // 定义订阅者类 class Observer { constructor() { console....

December 18, 2021 · 2 min · 258 words · Runtus

vuepress开发遇到的一些问题

vuepress是SSR渲染,即vue挂载之前是在服务端进行的,所以尽量不要在before Mounted之前的hooks中调用浏览器API,否则打包时会报错。 关于css中的 mix-blender滤镜模式,和 z-index关联比较多,具体体现在我在使用darkmodejs时,如何避免图片被mix-blender渲染,虽然官方给的方法是加入isolation:isolate属性(另启层叠上下文),但是并没有什么用,感觉是哪个地方出问题了,关于层叠上下文还有上述提到的属性需要重新学习下。 另外,层叠上下文z-index和position关联很大,这个也要去做深究,我如果只是给image加z-index,则无法避免被滤镜覆盖的事实,应该是需要把他们纳入统一个层叠上下文才行,所以需要position:relative(注意,position默认是static)。这一块儿的知识也要重点去温习。 const testFn = async () => { const a = 2; for(let i = 0; i < a; i++){ // xxxxxx } return new Promise((res) => { res(); }) } A-.->B

November 13, 2021 · 1 min · 37 words · Runtus

初入数据可视化

视图编码(可视化编码) = 标记 + 视觉通道 可视化设计的三部曲 可展示数据的筛选 -> 可视化编码映射(视图编码) -> 视图与交互设计 数据可视化设计的注意事项 在对数据可视化之前,要选择合适的标记和视觉通道,选择合适的视觉通道编码能够更加清晰,直观地展现出数据的特点,同时能够使用户更加容易地分析数据特征。 不同的视觉通道编码信息会产生不同的效果,这种效果也被称为表现力和有效性。 表现力和有效性决定着数据可视化的最终效果。 在表现力排序中,无论是定量型视觉通道还是定性型视觉通道,空间位置都具有最大表现力。 决定表现力的四个维度: 精准性 可辨认性 可分离性 -> 不同的视觉通道编码之间互相干扰的程度 视觉突出 -> 人依靠本能,在很快的时间内快速感应到图形中的异常点。此维度在发现异常数据的可视化分析中至关重要。 提升表现力的方法: 聚焦:通过恰当的技术手段就将可视化结果中的最重要的部分重点突出。 均衡:空间布局要合理,将重要的元素位于中心区域,其余元素均衡分布。 简单:元素尽量简单,避免画面过于复杂。 隐喻:尽量用人们所熟悉的某样事物去表达信息,从而使得可视化内容更加直观、易懂。 数据按照它们之间的特征,可以大致分为以下的三类: 数值型数据,分类型数据,有序性数据

October 17, 2021 · 1 min · 32 words · Runtus

保研说明

随便谈谈 距离上次写博客已经是一年前的事情,老博客的内容也因为自身的一些原因被丢失。同时最近在准备预推免复习时,突然发觉如果一天复习下来不进行总结,大概率第二天会忘记。 所以,为了能获得较好的复习效果,同时也是为了抓回写博客的习惯,又重新搭了个hexo的博客,希望自己能够坚持下去。 Github主题链接。 大三的遗憾 大三一年可以说是充满挑战的一年,但也是碌碌无为的一年。实习虽去了字节跳动,但发现进去依然干着搬砖的活。本以为可以写点SDK之类的,可惜因为人员缺乏,只能跑去写业务,累呀,也没有什么比较大的收获,因为除了写业务还是写业务。 于是乎,还是打算在六月的某日离职,全力准备夏令营(结果到头来是夏零营)。 不过都过去了,现在最重要还是眼前的预推免,希望自己能够坚持下来,将每日的学习总结以博客的形式呈现于此。

October 15, 2021 · 1 min · 8 words · Runtus