有一天咱们一个同学呢,问到这么一个问题,说,袁老师,你看一下这段代码神不神奇,好不好玩,让你实现这么一个函数,然后呢,让整段代码成立。我这一看吧,我在想啊,出这道题的人心里是得有多阴暗,有多病态,才能出出来,这种题他都不能用八股文来形容了。这位同学说呢,这道题是我出的, 那没事,挺好啊,这道题没啥问题。这道题呢,是一个思维训练。这道题是什么时候出的呢?是在同学们学完 es 六之后啊,出了这道题,主要是训练一下 es 六里边一些新学的语法, 以及 a p i。 我 们在 es 六里边学过了这个 promise, 是 吧?我们说 promise 以及这个什么 a sync 和 await, 这两个东西是用来消除回调地狱的,甚至这两个玩意儿呢,可以消除回调。但是呢,我们实际开发里边会发现,咱们注册事件的时候呢,这个回调仍然是存在的。比方说,我们拿到一个多米元素给它注册一个事件,你看这里的回调是不是依然存在, 那我们能不能想一个办法,把事件注册的回调也给它消除掉了?哎,这就是个思维训练,并不是说你在生产环境里边要去用这种写法,而是呢,给你一个特定的场景,特定的需求,看你能不能用学会的知识来解决问题。训练的是这种能力啊, 你看这里在尝试的消除回调,那在这段代码里边,我通过这个函数来拿到一个元素啊,通过一个 cs 的 选择器来拿到一个元素,然后呢,我要监听这个元素的事件,就不再使用回调去监听了,而使用同步代码的方式来进行监听,你看, 等待这个按钮被点击,等待它,它没被点击,代码在这里停住,不再往后运行,按钮被点击了,过后掉了一个方法好,然后下次循环,又等待下一次被点击,然后点击完了,过后又掉了一个方法,对 吧?又打印,就这么个意思。现在请你实现这个 get element 这个函数,它要接受什么呢?它要接受一个 cs 的 选择器,那么这个函数呢?我们首先思考一下,它返回什么?它返回什么呢?返回肯定是个动元素,是吧?所以说呢,我们这里呢,就可以直接得到一个动元素,把 cs 的 选择器传进去,最终呢是要返回这个动元素, 这逻辑没毛病吧?但是你光这样写的话肯定不行,光这样写的话,那个页面就直接卡死掉了,你看都已经卡住不动了,为啥呢?因为它陷入死循环了,你看啊,你这样写了过后,这个属性存在吗?在动物元素里边根本就不存在,是吧?所以说这里呢,就相当于是个 undefined, 那 你说等待一个 undefined 是 不是立即结束了?因为如果说这里不是个 promise 的 话,就相当于是一个什么 promise result, 那 么这个 promise 立即完成了,所以说打印,打印完了,下次循环又完成,又打印,就是 循环了,是吧?所以显的光这样子写的是不够的,我们还得去构造这么个属性出来,他不是没有这个属性吗?所以我们得去构造这个属性出来,对吧?我们思路呢,一点点去延长,其实我们平时在公司里做业务开发的时候,遇到一些复杂问题的时候,也是从简单到复杂,慢慢的去延长, 就是工具帮你写的差不多了,你想一想吧,这个属性应该是一个什么东西呢?你要等待它,等待还能等待啥?说等待个 promise, 因此这个属性呢,它得是个 promise, 对 吧? 那么这个 problem 是 什么时候完成的?哎呀,工具很讨厌啊,打乱我讲课的节奏啊。就是,这也提醒我们啊,一个很多一些体力活,就是你想办法已经到达那个位置了,很多体力活的事,或者是一些技之末节的事,拷一些工具就可以顺利的完成,不需要你操多少心的。这些事本来以前就不是很重要,现在就更不重要了。 同学们,以后啊,学习技术的关键点啊,就关注点,一定不要放到那些具体的敲敲敲敲敲,上面有啥好敲的,我就讨厌敲。你只要思路清晰了,你具备分析问题、解决问题的能力,这些敲敲敲的体力活,他对你的薪资高利和职业发展造不成任何的影响。 你要不要写呢?在你职位不高的时候肯定还是要写的,只是呢,你不要再过多的去关注他认为喜欢做项目,我薪资不高是因为我项目做的不够, 你项目够了,那我告诉你,项目绝对够了,不是因为你算术说的不够,是因为你项目里边解决的复杂问题不够。那个悄悄悄悄有啥复杂的?所以说很多时候我们不是同学们不学习,很多时候学习的时候呢,把时间都白白浪费掉了,要获得高质量高效率的学习,就好好来看我的大师课。大 师课是完全免费的啊,来领取。完事了,大师课里边我一句废话不跟你讲,我把所有前端最核心最重要,最能够直接影响你薪资高低和职业发展的知识依次非常密集的排列在你的面前。 学大师课那几天,你肯定会很辛苦,跑不了的,但是不辛苦不出效果呀,你只要花几天的时间把大师课认认真真学完,后面就不用我说了,你就知道该干什么了。而且你突然之间对未来很多事情呢,都有信心了,以后该走什么样的路,该学什么样的知识,学到什么样的程度,你就完全清楚了。而且大师课本身提供的知识 都已经完全足够你完成薪资的提升。这个课程啊,不管你在前端哪个阶段,一定是绕不过去的。关于这个课呢,目前可以免费领啊,怎么领?在咱们账号主页点击头像进入账号主页,根据提示领取,完事了 收回来啊。这个属性得是个 promise 吧,那这个 promise 什么时候完成呢?当然他点了过后,这个 promise 就 完成是吧?就注册点击事件好保存,咱们看一下啊,你看,这里,现在就没有死循环了是吧?目前在干嘛?在等待这个 promise 完成。什么时候完成呢?你点一下它就完成了, 但是你点一下过后,它为什么又不停的死循环了呢?这又是为啥呢?那你看啊,当你点击过后,这个 promise 是 不是完成了,那么打印了这个对吧?那么下一次循环是不是还是同样的 promise 是 不是又完成了? 所以这里呢,就遇到了第一个问题,我得让他每次读这个属性的时候,不要返回之前的 promise, 都要返回一个新的 promise。 这是第一个问题。我再说一次,我让他每次读这个属性的时候,不要返回之前的 promise, 之前的 promise 已经完成了, 再返回一个新的 promise。 好, 第二个问题,你看,我现在只是等待了点击事件,那以后我有没有可能去等待鼠标其他的事件呢?有没有可能去等待什么 focus 事件呢?有没有可能去等待一些乱七八糟的事件呢?是不?当然有可能,所以说我们还要考虑通用性是不是两个问题。因此这里的代码呢,就不能像这样子写了,我得把它改造一下。 也就是说,我只要监听到你读了一个以 wait 开头的属性的时候,我就要给你返回一个新的 promise。 我 再说一遍,我只要监听到你以 wait 开头的这个属性的读取的时候,我就要给你返回一个新的 promise。 那 这种监听在 es 六里边用什么样的东西来完成?是不是可以用代理对不对?代理不就可以监听这个属性的读取吗?代理?谁代理这个洞监听啥?监听? get target prop receiver 对 不对?就返回了代理,那么也就意味着它得到的是什么?不是一个直接的动,而是动的代理。这样子呢,你读这个代理的某一个属性的时候,是不是都会经过这个方法?那么这个方法里边是不是可以判断一下你这个属性的名字是不是以什么?以 wait 开头, 对不对?是可以做这样判断,换句话说,如果说你不是以 wait 开头的话,那么就是一个其他的属性,其他的属性我管都不管,该返回啥返回啥,对不对? 这个逻辑没毛病吧?那么剩下的事情是不是就是以位子开头的时候?那么以位子开头的时候,我要干嘛?要返回一个新的 promise? 你 每一次读我都要返回一个新的 promise, 对 不对?这个逻辑通了, 那么在新的 promise 里边我要干嘛呢?是不是还是一样的?是不是我要去监听这个 dom 的 某一个事件?那么监听啥事件呢?是不是我们要得到个事件的名字?事件名字是啥?就是属性名,对吧?把位子去掉不就完事了?那么处理函数是啥?处理函数就是 result 啊,当事件发生的时候你就完成, 那么这个事件呢?其实只需要监听一次啊,像这种代码结构呢,它就不会反复的运行了啊, promise 呢,只有唯一的状态,所以说呢,这个事件呢,给它加上一个 ones two, 表示这个事件只监听一次就可以了,就写完了,把它用代理就 写出来了。咱们首先看效果啊,点击,是不是点击点击点击点击点击,对吧?就实现了这么一种神奇的代码结构。这道题呢,是一个思维训练,主要是通过这道题看能不能充分的利用手上的工具来去解决具体的问题。最后用出来呢,就是一个 assign 和 await 以及 promise 以及 proxy 的 联合运用, 因为我们提升开发的时候,真正考验人的绝对不是你能不能实现你以前做过的功能,真正考验人的一定是你能不能实现以前没做过的事。那你什么叫没做过?那就不好说了,千奇百怪的情况都可能会遇到。主要这是思维训练啊,并不是说在生产环节一定要用这种方式。
粉丝16.9万获赞211.3万

各位使用 icon 放它的小伙伴们,你们是不是也有个这样的烦恼?就是每次添加了几个新的图标,都要再重新手动下载一次,然后解压后放到项目里,每次都要下载解压,很是麻烦,所以爱偷懒的我 写了个自动下载的小程序,它每隔一定的时间自动去监测有没有新的图标,有的话就自动下载并解压到项目里。除了第一次需要启动一下程序,后面基本上不用再手动下载解压了。 各位不妨也这样试试,真的很方便。需要我这个参考代码的自己去搜 icon font auto download。

好说一个在 vivo 里面的一个白屏优化手段哈,好,你看这个页面啊,我们这里刷新一次,你看他这里是有个明显的白屏和卡顿,是吧?要等很久很久很久很久,然后才出来。 那白屏问题呢,他是没有一个统一的解决办法啊。那要具体情况具体分析,你这个白屏到底是网络造成的呢?还是界是执行造成的,对吧?你先判断的是 方向,然后呢这个方向里边去细分,比方说你是网络造成的,到底是猫体过大呢,还是 c d n 的 问题啊,还是那个 d n s 的 问题啊,对吧?你要依次去判断的啊,这东西没有一定的规则,不是说白屏问题我就一定用什么方式来解决,那不一定的啊,你要找到问题的原因。 所以说我们这里呢,首先来分析一下啊,这为什么会白屏?我们可以打开一个性能分析工具 performance 啊,然后来录制啊,然后接下来刷新页面,好等待它完成啊,好,完成过后呢,我们这里呢停止录制,看一下目前的时间消耗啊,主要在哪里 好出来了啊?我们可以看到啊,下边有一个总览信息,这个信息里边提示的很清楚,我们目前的时间消耗呢,主要在 g s 的 执行上和这个渲染上,在这里呢一共就花了三秒多的时间,是吧?已经很严重了。那 为什么 g s 会执行这么长以前的渲染为什么会渲染这么多呢?其实很容易理解,因为我这个页面呢,它元素比较多,看一下我们的页面结构啊, 我这一个容器,然后呢我渲染了一百次重主键,这里呢,我实际上在模拟,模拟啥呢?模拟就是有些首页吧,他东西比较多,一大堆,各种各样的元素也很多 啊,但是你写的时候呢,可能不是我这样写的啊,你可能是这样的写的,第一个主键是很重的,主键里面有很多东西,还套支主键,套支主键套了一大堆元素,然后第二个主键又是一大堆,然后呢?第三个主键啊,我这里直接循环了,表示我的首页里边有很多的重的主键,这重的主键里边有啥呢?我们看一下目前的主键啊, 所以为了模拟啊,这个每一个重组件里面生成了五千个 diy 元素。当然实际情况下呢,可能是这个组件里边又套直组件,直组件里边又套直组件里边有一个列表,列表里边又有直组件啊,一大堆,反正就是元素很多。 那你想一想啊,当我们的元素有这么多的时候,是不是就意味着在 ui 层面,它要创建很多的虚拟节点,没问题吧?那创建虚拟节点是不是 gs? 是 gs 呢?它还要根据虚拟节点去创建,相应的真实动也是 gs 吧,所以 gs 呢,就大大的堵塞了浏览器的渲染。 然后另一个层面呢,就是五 u 啊,他那个真实动我们生成好了之后,是不是要交给浏览器,对吧?改变他的动数嘛。那么浏览器是不是要进入渲染管线,他把这些元素一个个画到页面上去啊,他得画出来啊,那由于这个元素很多,他是不是画的时间就很长,对吧?那么这就涉及到浏览器的渲染过程了啊,第一步,解析动,第二步 方式计算,第三步布局,对吧?一次完成七个步骤的渲染过程,所以说整个时间的消耗你看的很清楚了啊,一个是 view 层面的虚拟节点的创建,以及呢真实 dom 的 生成,另一个层面呢,是浏览器把它划到页面上去。好,那这里怎么来解决这个问题呢?我们的解决办法可以这样想啊,肯定用那个 react 的 时间切片的方式, 就是我们的首页里边东西可能比较多,但是呢,他一个市口范围内能够容下东西,他其实并不多,你看我们首页里边有这么多东西,对吧?但是呢,在首屏里边你看到的只有这一部分,这跟很多的首页是一样道理, 首页可能很大,但是呢,一开始用户只能看到其中一部分,因此呢,我们在渲染的时候啊,我们可以这样做,我们先渲染一部分,然后留点时间空隙出来给浏览器渲染,然后呢再生成另一部分, 也就是啥意思呢?比方说哈,我们的主键有很多,第一个主键和第二个主键,哎,这是用户一开始就会看到的,所以说这两个主键呢,我一开始渲染出来,然后呢第三个主键呢,我后边再渲染第四个主键呢,我过一会再渲染, 懂这意思吧?就是把那个渲染间隔给他拉开,这样子一来的话,虽然总的渲染时间是没有什么变化的,甚至还要增加,因为中间留了空隙嘛, 但是呢,用户的感觉上他的反应速度就很快。那具体来说,这一块我们怎么来安排这个渲染时机呢?哎,我们这里呢,可以用这个浏览器的渲染帧,比方说你呢就第一帧渲染,你呢?也是第一帧渲染,用户最开始看到就这两个,然后呢,你呢?就第二帧渲染,你呢就第三帧渲染啊,我们可以这样来安排。那具体代码层面的话,我们可以这样写啊,我们希望呢,有这么一个函数 叫做 different 吧,我给你传一个。一,你这个函数呢,给我返回一个 to 或者是 force, 表示啥意思呢?表示的是目前有没有到达第一针,哎,你到达第一针我就选它,对吧?我有个 v 符号,然后呢,这里也是一样啊, different, 那 么下边呢就是 different。 二,这样子是不是就拉开差距了,对吧?你呢是第二针选它,你呢是第三针选它。上面两个第一针选它, 意思吧,我就希望有这么一个函数啊,这里呢,我为了模拟啊,所以说我这里不这样写了啊,我就在这个循环里面写 if defn。 那 你是第几个主键,我就第几帧渲染啊,我是为了模拟啊,不要去申办硬套。好,那么现在我们是不是就缺失这个 def 方法了,对不对?那我们就导入一下吧啊,希望有这么一个函数叫做 use defn。 我 这里还没写啊, 我希望有这么个函数啊,从一个模块里面导入进来啊,然后呢一调这个函数呢,他就会给我返回一个 different 方法,那么后边呢,我们就可以使用这个 different 方法了,对吧?所以说我们现在就把这个函数给他补齐。好,这里呢,我再次强调一下啊,不要今天学了这个方法过后呢,以后见到一个白屏就去用,见到一个白屏就去用。 优化问题他没有定式的啊,他是具体情况具体分析。你看咱们大师课里面讲的优化讲了这么多,其中一个就是我们刚才说的啊,颜值装载 different, 还有很多的优化手段,甚至呢,你网络这一块层面他也有很多的优化手段, 这些东西啊,都在咱们大师课里面啊,而且大师课是完全免费的来领取。完事了,有的人说,袁老师,你为什么不直接拿一门课来讲优化? 我告诉你讲不了,为啥呢?因为优化关联的东西太多了,比方说 ui 层面的优化,它关联到整个 ui 的 框架的原理。工程化层面的优化,它关系到你对整个工程化的理解,网络的优化,它关系到网络渲染的优化,它关系到浏览器的底层原理。如果说我要开一个课讲优化的话,我就不得把框架、网络、浏览器工程化全部讲完,那不就是前端课程吗? 就你这个事情呢?再反过来想,比如说你对工程化是有深入理解的,那工程化的优化你不用学习,你秒懂,不用有任何人来告诉你工程化的优化该怎么来说,不用你自己就懂了,你把框架理解的很深刻,那么框架层面的优化你自己秒懂, 所以说不存在说有什么优化的课程要去学习优化没有这个东西啊,他全看你对整个前端的技术体系把握的深不深刻,你要达成这一点的话,好好来看大师课就完事了。其实大师课里边已经涉及到很多层面的深入知识了,同时也涉及到很多的优化问题, 而且观看这个课呢,目前可以免费领取啊,怎么领?在咱们账号主页点击头像进入账号主页,点击提示领取,完事了啊,好,现在呢,我们去实现这个 use def 方法。好,我们导出一个方法啊,叫做 use def, 这个 方法要干嘛呢?它返回一个函数,对吧?一个 def 函数,这个 def 函数呢,要接受一个数量 n 就 表示第几帧,那么这个要返回啥呢?返回的是一个 true 或者是一个 false, 那 么这个 true 和 false 的 意思是啥呢?就表示当前的帧数当前是第几帧吧, 当前是第五针,有没有大于等于这个 n, 是 不是一个逻辑?所以说我们现在要做的无非就是得到这个东西,当前是第几针?那于是呢,我们开一个 响应式的数据啊,叫 count 吧,好,默认为零啊,然后浏览器每跳一针,我这个数据呢,就加一,对吧。啊,这个东西其实应该写到外面啊,是全局的, 然后呢,我们就写个 update 方法啊,每调一次 update 啊,然后呢?它加加,然后呢?下一次再注册这个函数,对吧?下一层再来,对不对?一调就完事了啊?所以说这里要怎么判断啊?这里很简单,它就是 count 点 y 大 于等于 n 就 完事了,很简单,对吧?行,代码就写完了。好,写完过后咱们来看一下啊,现在我们刷新, 你看是不是瞬间就出来了,对吧?而且看一个滚动条是不是逐渐在缩小,说明它说明它是分布渲染的,再来一次啊,刷新,你看是不是瞬间出来了,对吧?浏览这个滚动条依次缩小,说明他后边在不断的加载 这样子的,虽然他的总的渲染时间,总的执行时间没有变,甚至还有增加,但是呢,给用户的感觉就是很快这个网站瞬间就可以看到结果,因为用户目前他只能看到这个第一个版面,懂这意思吧?这就是延迟装载的一个优化手段啊,还是那句话,优化呢,你不要死记硬背,也不要生搬硬套,具体情况具体分析啊,更多的优化手段来看 w 的 大师课。

好,今天呢,咱们来探索如何在地图上实现交互功能,在我们这个效果里边的交互功能是比较简单的,但是呢依然是涉及到很多很多的细节哈,这些细节呢,不仅是我们这个效果里边会遇到,将来同学们做其他的地图应用开发都是非常大的几率会遇到的。 好,这里呢我们可以看一下我们目前的交互功能啊,首先是一个鼠标一入,它会变颜色,是吧,然后呢随便点击一个呢,它会跳到相应的位置,并且呢显示一个路径,那么也就说重点的交互行为呢,就两个,一个是鼠标一入的时间,然后呢另一个呢就是鼠标点击的时间啊,点击过后呢就是会跳到相应的位置 啊,看上去呢非常简单哈,但是实际上呢,我们的交互要实现的话,会遇到非常多的细节啊,你看我这里的给大家的交互行为,他会遇到哪些细节?我们一个问题一个问题解决哈, 首先我们会发现呢,呃,无论是点击还是鼠标移入他这个飞机啊,他这个图标都会变颜色,对吧?就是我们首先要搞定第一个问题,就是如何来实现图标变颜色呢?我们先不管交互这变颜色的行为我得实现啊,目前呢我们的效果里边只有地图和飞机,但是呢这个飞机他是没法变颜色的, 那么如何控制变颜色?我到代码里边呢,我们之前设置的他的图标样式,其实图标样式里边呢有一个样式呢叫做 icon 卡了,就是指的图标颜色。好,那么这里我们随便设置一个啊,比方说我们设置一个 f 四零,好保存看一下啊,你看现在的图标是不是全部变成红色了? 所以说我们可以通过样式来改变图标颜色,但是这样做的话,有一个前提条件,就是你的图标呢,必须是一个 svg 的 图标,因为只有 svg 的 图片才能去动态改变颜色,你一个 png, jpg 的 图片是改变不了颜色的哈, 但是现在下一个问题马上就出现了,我们改变颜色的时候啊,并不是所有的飞机要改变颜色,而是只是某一辆飞机要改变颜色,是吧?也就是说我们在这个地图里边,它的颜色可能是多种多样的,有的飞机呢是这种橙色,有的飞机呢是这种红色,它是不一样的,那也就是说这个颜色它是动态的,它并不是写实的, 那这个问题怎么解决呢?哎,其实同学们看到上边都应该知道了,是吧?是不是可以动态获取这个 face 的 相关属性啊?啊?比方说我们在 face 里边呢,除了这些自定义属性之外,我们还可以给他加上一个颜色啊, color, 呃,比方说 随便来一个吧,来个绿色零 f 零,好,那么这边呢,是不是可以获取他的当前的 face 的 颜色啊?来一个 get color, 好, 保证咱们看一下呢? 好,你看飞机是不是全部变成绿色了,也就是说我们将来如果说要改变某一辆飞机的颜色的话,我们只需要去改变那一辆飞机他所在的 face, 他的这个 color 属性就可以了。 但是这样做呢,可能不是那么舒服,我们可能更加希望的是不要在这里去设置颜色,而去设置状态,比如这个飞机呢?他当前是不是鼠标移入的?就是当前这个飞机是不是鼠标移入的状态,而不是希望直接去在这里设置样式。 那么如果说有这样的一个需求的话,我们可能要换一种做法,就在这里头去设置这么一个东西啊,叫做 is harper, 把它设为零,表示这个飞机它鼠标是否移入,当然这也是一个自定义的属性哈,那么将来某一架飞机移入的时候呢?我把零变成一 啊,有的时候为什么不用 to 和 force? 呃,是考虑到一会的一个问题哈,一会就知道了。目前设为 to 和 force 倒是没啥问题,我们先把它变成零吧。 好,那么也就是说我希望在这里的颜色呢?它是一个动态的值,就是说这个 is harvard, 它为零的时候是一个颜色,否则的话又是另一个颜色,但是自己在这里不能用这种三目预算啊,为啥呢?因为这是初识样式,你后面这个属性会变的, 等你后面变了过后,这个样式就回不去了,所以说这该怎么办呢?好,这里呢有一个开发技巧啊,这个开发技巧呢,是以后你们做地图开发弄动态样式,会经常用到的啊。就是什么呢?就是我写两套样式。好,你看这是一套样式,我们把它取名为 normal style, 然后另一套样式,我们把它取名为 active style, 我 们给它做两套样式出来。那么这个 active style 呢?它跟 normal style 呢?差不多啊,就把 normal style 呢全部展开啊,差不多就多了一个 icon color, 把它设为我们希望选中的样式,就是红色,你看现在有两套了啊,一套是没有颜色的,没有颜色就使用图标颜色,对吧?那么一套呢,是自己给它重新定义颜色的,然后呢,有两套样式,我们在这里给他设置样式的时候来抉择到底你使用哪一套样式, 这也是做动态样式的一种非常常见的做法,那如何在这里抉择呢?那么这个时候呢,我们就需要给这个样式呢一个数组,你不是有两套样式吗?对不对?好,第一套样式,第二套样式,那么无非呢,我就是要在这里去写规则,什么情况下使用这套样式?什么情况下使用这套样式?每个样式呢?配置呢?是一个对象,对象里边有一个 style 属性, 这个 style 属性呢,就指向样式啊,这是 normal style, 那 么下边这个呢?呃,是那个 active style, 能理解这个意思吗?我现在要写一套规则,让它决定什么时候使用这个普通样式,什么时候用这个选中样式。这其实类似于啥呢?类似于 css 里面的 hover, 或者是什么 active, 或者是什么 link 这些尾类。 比方说我们写一个选择器 a, 它是一套样式,就是普通样式,但是有一些 a 元素呢,它是 hover 的 状态,那么这个时候呢,会命中另一个样式,懂这意思吧?好,那么这里具体怎么写?这个时候呢,我们要用到一个 特殊的配置,叫做 filter, 这个 filter 指的是什么意思呢?表示筛选,就是后边给的是一个条件,你只要满足这个条件。哎,我就使用这套样式,否则 else 这里写错了,满足这个条件,我就使用这套样式,否则的话我就使用这套。 那么这些样式是会针对每一个 spacecraft 来进行判定的啊,不是这里面有很多的 spacecraft 吗?对吧?有很多的飞机,一个飞机,一个飞机,它会自动拿出来啊,看这个飞机是不是满足这个条件,满足条件的话使用它,不满足的话使用它,能理解吗?好,那么这个条件怎么写呢?那就是具体的语法规则了啊,不重要 啊,我给大家写一下吧。你写了过后一看就明白了啊,条件是判断是不是相等,判断啥?是不是等于零啊?你看一下,是不是跟那个零是相等的,就这个意思, 相等的话就是普通样式,否则的话就是特别样式啊。保存,咱们看一下啊,你看一开始都是零,是吧,那就是普通样式。然后呢,我们这里呢,如果说把它改成一的话啊,保存你看一下, 你看是不是变成选中的样式了?那如果说你希望某一架飞机改变它的颜色的话,是不是把那一架飞机的飞行器给它设置为一,其他的保持不变不就完事了吗?那么后边我们是不是可以通过它来控制,对不对? 而且呢,我们将来不仅仅是有可能鼠标移入,是不是还有可能会选中啊?你看我们这里,呃,选中某一架飞机,是不是他也会保持住这个样式啊?哎,飞跑哪去了?在这啊,他是不会保持住这个红色的样式。所以说呢,这里有两种状态啊,一个是是否是鼠标移入,另一个呢?是是否是被选中啊?比方说我们这里呢,一直 send a t 的 再加一个属性是不是被选中?那现在我们的条件是不是要变化?无论你是鼠标移入还是你被选中,无论是哪一个,你是不是都要变红色? 那现在我们条件稍微改一改啊。什么条件呢?其实非常简单,就是把这个一是 half 的 和这个一是 sinect 的, 这两个数字加起来,加起来还等于零,是不是你就是既没有选中也没有鼠标移入,那你保持原始的样式不变, 否则的话那要么就是你被鼠标移入了,要么就是你被选中了,那么你就改变颜色。所以为什么要用数字呢?就方便会被处理啊。那这里具体怎么写呢啊?那都是具体的语法了,同学们去查文档也好,看我们的课程也好,或者是啥也不用管,你直接一看就明白了啊,要干嘛呢?就是要加 啊,他是有很多的运算符的啊,这里边他支持很多运算符。把这个属性拿到,然后呢再把这个属性拿到,然后把两个属性加起来,看一下加起来的值和这个零是不是相等,一看就明白了啊, 好保存。那么一开始呢是肯定是颜色不变的啊,然后后续呢,我们如果说改动任何一个啊,比方一致性的改动了这一个,然后呢他就会变成红色,或者是改动这个一致的都是可以变成红色的啊,你看对吧?好,所以说现在我们第一个问题解决了啊。呃,就是如何来动态改变 飞起来的样式。其实这里的做法有很多啊,我这里只是提供一种非常常见的做法,其实还有很多其他做法,就是做地图应用啊,特别是 openlayers 里边这个框架里边呢,做地图应用是非常非常灵活的,他做法非常多,不同的场景下我们可以使用不同的做法。在我们后续的课程里边,还有像 openlayers 课程里边, 我们会讲一个完整的 openlayers 项目,这里会涉及到更多的样式控制。我们整个 openlayers 课程呢,从二 d 地图到三 d 地图,全部给讲完了的,还包括前端、后端、全站全给讲完的 啊,一开始是地图概念,然后呢是 openlayers 框架,呃,然后是 openlayers 项目,然后一些其他的二 d 地图的框架是 live flash 啊,因为你不同的公司的话,他可能用的地图的框架是不一样的,然后包括后边的一些全站的,呃,服务,还包括数据库,可以讲完了的,还包括三 d 的 地图 c, 三 d 地图要稍微复杂一些啊, 所以说你要获得完整的呃 webkins 的 相关知识的话,那么请来看咱们的完整课程啊,了解这个课程的方式在咱们账号主页点击头像进入账号主页,根据提示来找咱们了解就可以了啊。好了,现在我们知道如何来控制样式了,现在就是下一个问题,我们什么时候改变哪架飞机的 样式?所谓改变样式,无非就是改变啥就改变这个属性啊。那么首先遇到第一个问题就是事件了,什么时候去动这件事? 所以下个问题啊,如何来注册事件?注册事件的话,我们需要这么一个东西,就是 map 对 象,就因为我们在开发过程中遇到的大部分事件处理都是要挂到 map 上的,你说其他的雷啊,像这些尘有没有事件呢?他也有啊,每个尘啊,灰尘啊,这些都有事件。只不过呢, 我们处理什么用户交互的事件都是基于 map 的, 所以我们事件要挂到 map 上,因此呢,为了让这个代码结构清晰哈,所以这里呢,我们去新建一个模块啊,叫做 events, 叫介事啊,专门来处理各种各样的事件,这里呢,导出一个函数哈,呃,叫做 attach events, 你 把地图传给我,我来给你处理地图上的各种各样的事件。好,那么在 index 里边呢,我们就直接来一个 attach events 就 可以了啊,看下面有没有导入,导入,导入一下啊。好,那么接下来我们所有的事情的重心就放到这个 模块里边啊。首先说一下,这个模块里边一会的代码会稍微比较多啊,而且东西比较细,朋友们不用去关注那么细的东西,因为我们现在毕竟有很多的 ai 工具了,可以帮助我们去处理各种各样的细节,你只需要去把控代码的整体方向,以及学习到你的一些关键环节就可以了。 好,跟着我的思路走啊,你是一定能听得懂的。那么这个事件里边,我们目前要处理两个事件,是吧?一个是鼠标移入事件啊,这是这个事件。另一个呢是鼠标点击啊,点击过后呢,他会有相应的动作啊,就点击事件。 好,就是处理这两个事件,因此我可以把这两个事件呢分别写成两个方法啊,一个是 attach 呃, move event, 把地图给我,呃,一个呢是 attach click event, 好, 就这两个事件。那么有了这两个函数过后呢,我在这里是不是调两个函数就完事了啊,分别去处理这个移动事件和点击事件。 好,那么怎么来注册事件呢?好吧,首先处理移动事件啊,在移动事件里面,首先遇到第一个问题,就是我们现在有个 map 对 象,有个地图,那么如何来处理事件呢?非常简单啊, map 里边呢,有一个 on, 对 吧?监听事件自动不用解释了吧,还有啥好解释的?事件名称,事件的处理函数,对吧?就完事了,那么点击的时候也是一样啊, click 啊,然后处理函数。好,这就是注册事件的方式。好,于是把这个问题搞定了啊,好,我们现在就进入到鼠标移动事件,我首先把整个事件的处理逻辑代码结构给它写出来,然后呢,我们再去处理关键环节。 好,这代码结构写出来了啊,我们来读一下啊,这里面有些东西现在还没有实现,但是呢,它的结构已经出来了,这个结构非常简单,我们首先用一个变量来定义之前 鼠标悬停的 feature, 然后鼠标一移动,那么首先做一个判断啊,如果说目前是以拖动的方式的移动的话,就不用管它啊,什么叫拖动方式的移动?就是必须要这样子拖动,这种移动就不用管它了啊, 那么这里呢,通过了事件参数域的一个属性,就可以判断它是不是正在拖动当中。然后呢,如果不是的话,那么我们首先要移除掉之前的 hello 状态, 因为现在鼠标可能移入到一个新的飞行了,对吧?那么要把之前的这个飞行啊,如果说它存在的话,那么要把它设置为 no, 然后呢?接下来就得到当前鼠标位置的飞行,然后把当前的飞行呢,把这个 left 设置为当前飞行,这个代码不用解释了,如果说你看这个代码都有困难的话, 各位同学,你现在需要的可能不是杂七杂八的各种各样的知识技巧,你需要好好把你的基础打牢哈,我不是跟你开玩笑的,如果说这个代码啊,你看上去有困难, 那就是开发能力的问题了,因为我知道技术啊,它等于两个方面,一方面呢是知识,就是你的工具啊,什么框架呀,那些 api 熟不熟啊,什么 ai 用的六不六啊, 这些都是属于知识层面,就你知不知道有这个东西?同时另一个还有很重要的一个层面就是能力,什么叫能力?就是给力,这些东西把工具全部给你, api 全部给你,文档全部给你,我现在有个需求,你能不能实现,你能不能去组合应用这些工具把问题解决,这就是开发能力,这两者缺一不可哈,有能力没知识, 那么就意味着很多方案呢,你根本就想不到,因为你缺失那一块的视野,你不知道这个地图上那一块还有东西,你有知识没能力把所有东西给你了,你也解决不了问题。 而这两个东西呢,都是随着学习,随着培养的,无论是我们的体系化课程,高新课也好啊,加过课也好,这两个课程是从前端零到毕业的课程啊, 什么叫毕业?就是毕业的意思,就是没东西了,除了咱们的付费课程之外,我们的福利课程里面也在不断的培养大家的知识和能力,不但去讲各种各样深度和广度的知识,同时呢也在不断的去提升大家应对各种复杂问题的开发能力,无论是咱们的付费课程,还是我们的福利课程,你看完之后都会大有收获。 这课程怎么来领取?还是一样啊,在咱们账号主页点击头像进入账号主页,点击提示领取就可以了啊。好,我们的接下来就来做填空题了,就代码里边有些地方呢,还没有实现,我们把它实现就完事了啊。首先看这个地方,我们要获得鼠标当前位置的 feature, 就是 我们现在遇到的第一个问题啊,如何获取鼠标所在位置的 feature? 怎么获取呢?这里是有个方法啊,非常简单啊,叫做 map get features at pixel, 它传入两个参数,一个参数呢是当前的位置, 一个参数呢是位置,就是你要传出一个坐标啊,横坐标,重坐标。那么这里我们当然是把鼠标的位置给它传过去啊,这个 e 里边有一个皮革球啊,这些东西都是 a p i 细节,不用去管它啊,总之它可以获取到当前位置, 把当前位置给它传过去。然后呢后边是做一些配置,这个配置里边可以做一些细节的处理啊,比如说这个 hit tolerance, 这是什么意思呢?表示一个可容忍的范围,因为有的时候鼠标点啊,它的一些东西比较小,点的没有那么精确, 那么给他三个像素的容忍范围啊,就是哪怕你挨着三个像素没有真正的点到,那我也算就这个意思,那么这个函数的作用呢?就是把这个位置的所有的 fitter 返回给你 啊,其实说是所有 fitter, 实际上他只会返回一个。呃,这里为什么会只返回一个呢?有些地方不是有飞机重叠吗?那为什么只返回一个啊?这是因为我们目前呢用的是这个 webgl 的 vector, 拿这个维克特的话就是个问题啊,就有这个特点啊,不用去管他啊,返回一个就一个呗。所以说我们这里呢,就可以拿到这个 features, 他 返回的是个数组啊,但是实际上是个数组,只有一个。拿到当前的 feature 啊,就是 harvard, feature 就是 他的第一项。 好,那么我们把这个地方替换一下啊,这就是拿到当前鼠标位置的飞行的方式啊。这里呢,其实还有一个小细节,什么呢?就是我们知道意图里边不是有很多层吗?对不对? 那我现在呢,要拿到的 face, 他 在哪一层呢?他如果说不去控制的话,他就把所有层的 face 全部拿给你了,比方说我这一层,哎,上面有一个东西,一个 face, 然后上面呢,地图上又盖了一层, 上面呢,他也在类似的位置啊,也有一个 face, 那 么当鼠标在这个位置的时候,他到底把哪一层的 face 给你呢?所以说我们一般情况下用这个方法的时候,都会做一个层的筛选,你只把某一层或者是某几层的 face 给我,其他的 face 呢?我不关心。那怎么来筛选呢?这里有个 la filter 啊,就是一个层的筛选器,它会把每一层的对象传给你,你要返回一个布尔值啊,就是看一下这个层是不是满足条件,那么这个层怎么来筛选我们这一块呢?就可以用这种方式,我们之前不是有个层吗?在这里每个 layer 对 吧?有它的圆,有它的样式,那么给它加上一个自定义属性,比方说 name 吧,呃,叫做 planes 啊,就飞机这一层就是自定义属性啊,然后在这边呢就可以进行筛选了啊,我们就可以用 layer get name 是 不是等于这个 planes? 那 么我这样子的话,我们只看这一层的 face, 懂这意思吧?这样子就拿到了鼠标移入的 face 了,好,那么现在这个问题是不是解决了,对不对?找到鼠标当前位置的 face, 好, 我们给他打个勾啊,好,下一个如何来设置 face 的 属性?也就说我们拿到这个 face 了,我们的目标是啥?不是要把它那个之前那个一是 hardware 的 属性给它设为一吗?对不对? 那么这个属性一变,是不是后面的样式就跟着变了?因为后面的样式是根据这个属性来进行控制的,对不对?所以说呢,我们这一块拿到个 face 过后,我们要把它 设置为一啊,那咱们来设置非常简单啊, hover feature cs is a hover feature 为一就完事了。那么同理呢,之前移入的 feature 是 不是把 is a hover feature 设为零啊?之前这里把图标去掉啊,那么我们就在这里去 master hover feature, 把 is a hover feature 设为零。我们只关注关键环节哈,有代码结构,你看不懂找咱们领课去啊。 好,其实现在都已经能够看到效果了啊,保存,你看鼠标移入这效果是不是出来了? 好,接下来还有个小问题啊,就是,呃,这个鼠标样式的问题,当我鼠标一入过后呢,这个样式呢,我希望把它变成一只小手,而鼠标没有在的时候呢,样式呢就回归正常,那这个东西怎么做呢?那这个东西呢,就是普通的多母的处理了啊,因为我们整个的地图呢,是放到一个多母容器里边的, 你看我们放到哪的,放到这个地方的,对吧?放到这个容器里边的,我们只需要控制个容器的鼠标样式就可以了,那么这里就会遇到一个新的问题,就我在这里怎么拿到这个容器呢啊,就这个问题了啊,如何来更改这个容器样式?怎么拿到这个容器?拿到容器的方式很简单啊, map 里边本身就有一个属性,叫做,呃, map get target element, 那 么通过这个方法呢,就可以拿到这个地图所在的容器,这就是个普通的东盟对象。好的,打印看一下吧, content 保存,你看一下好,看了没?这容器是不是拿到了?好,那么拿到容器就简单了,我们这里呢,更改这个容器的样式为小手,是不是就是这个 container style, ctrl 把它设为 point, 然后呢,下边是一样的道理啊,把它设为 default 就 可以了,好保存啊,大家看这鼠标样式是不是就正常了,对吧?好,于是呢,我们这个问题也搞定了, 你说鼠标移动事件是不是没啥事吧?好,接下来是鼠标点击事件,好到代码里边去啊,还是一样,我先把点击事件的代码结构给它写出来 啊,看一下点击的代码结构啊,其实都写的差不多了,一看就明白了,这是上一次点击的飞机,好,然后我们注册点击时间, 鼠标拖动的时候呢,啥也不用去管它。然后呢,如果说有上一次点击的飞行,因为我们可能点击的新的一个嘛,对不对?就是把上一个的点击的状态设为零,然后呢,上一个把它置空,接下来是会拿到当前鼠标位置,点击那个位置它所在的飞行,对不对?拿的方式跟那个 hover 是 不是一样的 啊?拿到他啊,拿到第一个就可以了,然后呢,如果说他存在就是你点了东西了,有可能你没有点东西啊,因为有可能是点的地图的其他地方,对吧?那么点的其他地方的话,我就啥也不处理,如果说你点了东西的话,我就把它的状态设为一,对吧,表示选中了,然后给这个 let's click 非常扶持, 那么现在这个东西又变成上一次点击的东西了,对吧?就这个逻辑,好,看一下啊,看一下效果,点一下是不是变化了,再点一下是不是变化了,对吧?点空白了它就消失,因为点了空白过后,是不是这句话会运行,对吧? 好,但是我们现在还差一点东西,什么东西呢?就是我们点击过后呢,他要挑到相应的飞机这个地方啊,点击过后,你看他是个动画挑过去的,那么这里呢,就涉及到那个重设地图中心点的问题, 什么意思?你看哈,比方说我点这个地方,那么我鼠标点的地方是不是目前的地图中心点?并不是,目前的地图的中心点,在北京这里,对吧?在这里, 那么我们现在点这个地方,你看地球中心点会变,他会变到这个飞机所在的位置,懂这意思吧?所以说呢,我们这一块呢,会遇到第一个问题,就是如何来重设中心点。在哪里重设呢?肯定是在这里需要重设中心点。 那么从事中心点的话,首先第一个问题就是我如何获取到当前飞侠的位置,为什么要获取当前飞侠的位置?因为我要把中心点收到了一个飞机所在的位置啊,那我肯定得知道飞机在哪啊,对不对?那怎么来获取呢?非常简单,一句话就完事了啊,可得个飞侠就这句话啊,你让 ai 给你写也行, 你查一篇文档也行,反正都能写得出来。 face 里边不是有个 geometric 吗?对不对?你看我们之前设置 face 的 时候,是不是设置了个 geometric, 把这个 geometric 得到,然后得到它的 coordinate, 就 它的坐标,这个数码就是一个数值啊,我们来看一下啊,啊, center 打印一下啊,复制啊, 然后打印这个 center, 好, 保存,你看一下。好,现在我们点一下啊,点,你看,就他的坐标,你看,随便点一个啊,再点,你看是不是他的坐标,对吧?好,拿到这个坐标过后,那么下一个问题来了,如何来重设中心点呢?也很简单啊,就是使用这个 map 里边不是有个 get view 吗? 可以拿到这个 map 的 试图。为什么要拿到试图?因为中心点呢,是在试图配置里边,你看我之前的中心点是不是在试图配置里边,是不是好拿到?试图过来一个 set center, 好,把这个声卡传进去,把这串保存看一下,好,到这边来。好,点击,你看,点击,你看,中心点是不变了,看到没?点击,再点击,你看,是中心点变了,但是这个中心点是没有动画的,我们如果说希望用一个动画来实现过渡性的变化,该怎么办呢? 也很简单啊,在 view 里边呢,有一个方法啊,叫做 animate。 好, 一看就明白了啊,这个需要多解释吧?没啥好解释的啊,让它在五百毫秒内重新点变到这个位置啊。保存,你看一下。好,点击,你看是不是有动画效果了?点击 点击,点击,你看是不是过渡效果了?那如果说还需要放大的话也一样啊,动画呢,是可以添加多个帧的,这是一个动画帧,然后逗号下一个动画帧,然后这里呢,我们把它用 room 来放大。放大多少倍呢?就十二嘛,好,保存,你看一下,就两个帧了,是吧? 再来啊,比方说这里点击,你看是不是过去了,对吧?先跳到它中心点,然后再放大,再来一次啊,点这个点击,你看是不是过去了?然后点这个点击是不是过去了? 于是呢,这个问题是不是也搞定了?好,下一个问题啊,添加路径层什么意思?你看这边啊,他是个路径的,看到没添加路径层,那么这个路径层显得并不是一个飞机,是不是我们还要多一层东西啊? 我们之前用一个向量层去画过点,对不对?也画过飞机,那么如何来画路径呢?其实是一样的啊,我们到那个 layers 里边去,现在呢,我们不仅只有一层了,我们现在目前只有一个飞机层,对吧?我们还需要多一个路径层。好,于是呢,我们把代码结构呢稍微的处理一下哈, 我们这里呢,写上这么一个函数,呃,创建飞机城, create plane。 好, 把之前的代码啊,就创建飞机城的代码全部弄过来, 避免代码臃肿,然后呢,把这个城返回啊 planes there。 好, 那么这边就调用这个啊, create planes, 然后呢,把这个 layers 展开。好,接下来我们再写个方法,创建路径城, create pass, 那 么同样的它又要返回一个宿主啊, 因为他有可能是有多个层的,你要考虑到后边的扩展啊, python, 这样子呢,我们把这里合并一下,返回这个代码结构,看上去舒服多了,是吧?好,那么如何来创建一个路径层呢?道理还是一样的啊,还是来一个 layer, 又一个 vector 是 一样的啊,配置城里边配置啥?前面说过的是吧?配置有数据源,数据源是啥?还是一样的啊?就是 vector source, 然后我们数据源里边是不是有很多的飞机圈?我们之前是飞机,现在是一个一个的点连成了线了,对吧?好,然后呢,我们把这个 layer 返回啊,好,那么这里呢,首先遇到的第一个问题就是我如何在这里添加点,以前是怎么添加点的?之前创建飞机的时候是怎么添加点的? 是不是一个一个的 point, 对 吧?每个飞行呢,是一个飞行对象,然后飞行对象里边是不是有个点,那么这里呢,其实是类似的哈,但是呢,有一点不太一样,我们这里呢,来,先创建一个飞行啊,又一个飞行,这里哪点不一样呢?你看他是这告诉你的啊,由于你后边要连线,所以说你创建的时候呢,一条线就是一个飞行,而不是一个点,是飞行 之前的飞机呢,是要把这个点变成一个点,那么现在是线,那么就一条线连在一起的一条线就是一个飞行。 那么如何来表示连在一起的那条线呢?那这里就不再是 point 了啊,表示一个新的对象叫做 line string 啊,我们需要导入啊, 导入一个 line string, 那 么这个 line string 里面竟然是线,它是不是有多个点啊?那这是第一个点啊,这是第二个点啊,我是通过经纬度转换的啊,这是北京的经纬度坐标。把它转换成一个点的坐标啊,默化多投影,我们之前讲过的,是吧?呃,比方说我们现在做一个例子吧,北京到上海的一个连线,我们问一下,上海的位置在哪? 上海的经纬度坐标在哪?呃,是这个啊,我要复制一下啊, 然后北纬复制一下。好,再来一个点吧。呃,再到深圳吧啊?深圳的经纬度坐标在哪?好,再来一个。呃,这是幺幺四。 北纬,这个复制一下啊,好保存。这样子呢,这个飞船里边就有一条线,这个线里边是有三个点连起来的,对吧?这是起点,这是中间点,这是终点,好保存,你看一下。哎,我们的线跑哪去了呢? 线跑哪去了?这是因为我们没有设置样式啊,我们现在只是把那个路径点要添加进去了,那么路径样式我们还没控制,是吧?所以说我们这里呢, layer 里边除了这个 source 之外,是不是还得有一个什么 style? 样式的话,是不是去查这个 openlayers 文档就行了啊?我们之前查过的啊,现在就不再重复查了,给它控制一个线的样式,线宽和线的颜色好保存看一下。呃没有效果是吧没有效果那就得查文档了啊。那可能 ai 给你写的是错的。 好到 a p i 里边去搜一下啊。 flat 好 到这个线线没有这个 line 是 吧。没有这个 line 的 样式应该是个 stock。 呃看一下啊对,就是 stock color stock with。 好 保存 到这边来。你看线是不是出来了。看到红色的线没有。从北京连到上海再连到深圳这一条线就出来了,只不过这个线不是写死的对吧。我们现在是把点写死的。那线应该怎么办是不是动态加的呀。因此这个数组呢一开始呢我们把它保留为空啊保留为空啥都没有。那么后续呢我们再去加好。于是呢这个地方是不需要 nice 俊的啊。 总之我们现在知道了如何来控制路径的样式那么后续呢我们就可以去给他添加点了啊。什么时候添加点是不。点击飞机过后我们到点击事件这里来 你看我们点击飞机过后除了要做这些事情之外是不是还要添加路径点啊。我们要生成一个些路径点给哪个地方加进去给这边这个雷尔加进去对吧。我们给这个雷尔的一个名字吧 name 为 pass。 到这边来我们封装成两个函数,一个呢,就点击过后我要添加路径啊,就 add pass 把当前的这个飞机的位置告诉他让他根据这个飞机去添加路径。那对应的啊除了添加路径之外我们是不是还要把路径给他删除掉。就把上一次点击的飞机的路径给他删除掉啊,这里有一个 remove pass, 比如说我们现在需要两个方法啊,一个是添加路径的方法,一个是移除路径的方法好,于是呢,我们在这里啊,下边写两个方法,一个是添加路径 pass, 你给我一个 face, 那 么我会基于这个 face 呢?去添加路径,注意这个 face 是 什么?是飞机啊,我给他写上 plane feature, 然后呢, remove case, remove case 比较简单啊,就全部移出去就行了啊。 好,看下这两个方法如何实现好。首先是添加路径,添加路径,我是不是要得到当前你点的那个飞机目前它经历的路径点,对吧? 那这个路径点怎么得到呢?我们之前是有这个 api 的 啊,就是这个 track 传入飞机的 id 就 可以拿到它的所有路径点。好,咱们来把导入一下啊, import track 好 到这个函数里面来。首先呢,我们拿到这个飞机的什么 id, 对 不对? get 二十四啊,拿到,你点击这个飞机的 id, 我 们看一下吧,保存,看一下 id 能不能拿到。呃,点击某一个飞机,你看 id 是 不是拿到了,对吧?好,拿到这个 id 过后呢,通过这个 track 把 id 传进去 啊,等待一下啊,就可以拿到它的所有的路径点。呃, pass 好, 大家看一下啊,保存, 点击某个飞机,你看是不是找到一个数组,数组里边这是其实的位置啊,经纬度,你看经纬度,经纬度,每个都是经纬度,那么现在我要把这个数据结构来做一个转换,我要把它转成什么呢?转成这种格式啊,这第一个点 x 和 y, 然后第二个点 x 和 y 是 不是要做一个转换?那么来做一个转换非常简单啊,我们把这个设置为一个 let 好, pass, 重新干,复制来一个 map, 目前呢是一个经纬度是吧?经纬度的话,我给他来一个结构吧。 no dot。 好,那么通过我们之前的辅助方法 from longnet, 是 不是把它转换成一个个的点?好,我们再打印一下啊, pass 保存,你看一下。 好,点击,你看是不是拿到了它所谓的路径点了,这就是我们想要的数据结构。好,因此呢,这个问题就解决了啊,如何来获取路径点?好,那么现在获取路径点过后呢,我们要干嘛呢?是不是要像之前一样啊,在这里边给他加 feature, 加一个 feature 就 可以了。好,于是呢,到这边来啊,我们首先要拿到这一层,就是这个路径这一层 好,怎么来拿这个路径那一层呢?我们可以通过 map 去拿啊,找到一个 pass layer。 map 啊,他给写出来了,通过 find 方法可以筛选某一层啊,这个不用解释吧,一看就懂了啊。我们来打印看一下这个 pass layer 能不能拿正常拿到,因为有的时候 a i g 写代码呢,写的是有问题的啊, 小心啊,他说 find 也是拿着方形啊,他不是一个数组,呃,他是一个可类形,他是个尾数组,尾数组里边是没有这个 find 方法的,所以说呢,你这一块呢,需要把它变成一个数组啊,这里我们可以用那个 get 二瑞啊,它里边是有这个方法的,把它得到一个数组,然后去找这一层好,保存,看一下,小心。 好,现在可以拿到了,是吧?拿到这个类二层过后,那要得到里边的 feature 是 非常简单的,按照我们之前理解的结构怎么弄的?城里边有啥?是不是有 source, 对 不对?有数据源,数据源里边是有 feature 对 吧?是不是?我在这里去哎,添加一个 feature 就 完事了。 add feature, 然后另一个 feature 啊,这些东西都需要导入哈。 导入一个 feature 啊,还有 landscape 好, 然后添加一个 feature, 这个 feature 里边是啥东西呢?就是一个线啊,有这个 pass 连成了一条线,加进去不就可以显示了吗?好,保存,你看一下啊,这里又冇错了啊,有的时候一写的东西莫名其妙啊,我先导入 feature 吧,好,分开导出啊,好,保存,再来一次啊,刷新。 好,现在我们点击一个飞机,你看一下线是不是出来了,对不对?这线就出来了啊,然后再点击其他飞机呢?我们看一下其他飞机,比方说北京这一块的飞机啊,你看这线是不是就出来了,对不对?看到没?然后点击换一个飞机 啊,这个线是不是就出来了?那么只不过呢,现在目前之前的线是不是没有移除掉?所以说我们要实现这个方法啊,就是移除之前的线。那怎么来移除呢?就是把所有的线给清除掉就完事了。 他给你写了一个什么 get source, clear。 我 不知道这个有没有这个函数啊,我觉得悬吊吊的啊,再点击啊,这个没问题啊,然后呢?再切换,然后好像是没问题啊,再点击啊,这样确实清楚掉了啊,那就 ok 了。好,因此呢,现在路径点也加上了啊。 好,这个问题搞定了,那么剩下的就是最后两个问题了啊,就是一些疑虑问题啊。第一个问题呢,是如何把点击的飞起来,或者是鼠标移入的飞起来放置到最上层, 目前呢,看上去好像是没问题的。你看我们鼠标移入,它始终在最上层,目前是没问题的,那是因为目前的代码呢,就恰好是没问题。你看这里就是在样式里边呢, active 的 样式,我是把它写的靠后的。在 webgl 的 渲染过程中啊,它这个靠后的样式呢,它的处理就是在最上层。 那如果说你不是这样写的,比方说你换种写法,你 filter 是 用大于写的啊,就是这两个东西加起来是大于零的话,那就是激活样式 active 在 上面, 那么 normal style 呢?在下面。那如果说是这样写的话,保存你看一下啊,他就会出现这个问题,你看鼠标一弱的时候,他的红色,你看在下面遮住的,看到没被遮住的。如果说啊,有的时候你不太好控制,就出现这种情况, 你如何用一种最保险的方式就保证他百分之百,无论你怎么弄,他一定在最上层,这个怎么来弄,其实很简单, 你给他加一层就完事了。那有的人说用 z index 来控制,呃,不好意思,这个 webgl 呢,它是不支持 z index 的 啊,如果说一个普通的维克特向量层的话,它是可以的,但是呢, webgl 它是不支持这个单个元素的 z index 啊,因为我们知道 webgl 的 渲染它是一体化渲染的, 它很难去单独去控制渲染顺序,所以说没办法啊。呃,这一块呢,我们如果说要保险的做法的话,该怎么来做呢?就要多加一层,就是下边那一层只渲染普通飞机,上边那一层呢?渲染激活的飞机,懂这意思吧? 就这么要多加一层啊,就是下面的普通层呢?我就是一个普通的 normal style 就 可以了,然后那么单独的去加一个叫 active plane layer。 好, 你看我们现在导出两层,一个是普通层,一个是激活层,激活层在后面渲染,所以说它一定在它上面, 但是这里要注意啊,激活层虽然用的是同样的数据源,它这个数据源里面有很多飞机的,我需要渲染那么多飞机吗?不需要,我只渲染它带有激活状态的飞机就可以了。所以这个 style 是 不是要用过滤对不对? a 钥匙就不要了啊,我只渲染 ishopper 的, 加上这个 islekt 的 大于零的这个飞机,那么只会渲染几个一个是不是 同样的?你在这边呢,也可以这样写啊,我们只渲染它等于零的飞机,那个鼠标移入的飞机,或者是选中的飞机,我就不渲染。当然在这个层的话呢,不渲染的飞机只有一个。其实代码写不写都无所谓的啊,因为毕竟只有一个飞机嘛,多渲染就多渲染一个。那没事的,在这边一定要写,不然的话就多渲染很多个了,好,保存,你看一下啊。 好,你看现在是不是又没问题了,对吧?放大一点啊,你看是不是又没问题了,始终在最上层了,对吧?点击过后呢,也没问题。好,这是这个问题,把它解决掉了。好,下一个问题呢?也是地图开发中经常遇到的问题啊,就是无缝拖动带来的问题。什么意思呢?就是说我们来看一个例子。呃,假设呢?我们现在取消选中啊。 呃,我这里拖动地图啊,因为这是个无缝拖动,你看可以一直这样拖动,拖动过后呢,我们现在随便点一个飞机啊,你会发现这个耗费没有了,点击事件也没有了,你看是没有了,那这是怎么回事呢? 我给你画个图啊,就是我们点击坐标啊,他是在一个市口以内,你无论去怎么拖动这个地图,点击坐标都是一样的,比方说我们点击的是这个点中心点,假如这个中心点是五十和五十啊,假如这个市口范围是零到一百嘛,那么点击中心点就是个鼠标,位置是在五十乘五十, 然后呢,你拖动地图,拖动地图拖动了很多次了,过后呢,你再点中心点,他还是五十和五十,就鼠标位置是不变的,他是相对于市口的,但是这个地图位置可变了,这个地图坐标都不知道跑到哪去了,那么就会导致一个换算关系的问题, 所以说为了处理这个换算关系呢,我们一般会加上这么一段代码哈,这代码呢,我们大概说一下意思就行了啊,基本上代码写法是固定的,好到一个事件就是处理这个拖动事件啊, attach move and event 这里呢?去 attach 一下啊。啊,他这个代码写的不对啊,就是移动地图结束的时间,移动地图结束了过后呢,我要把它回归到原位置,什么意思呢?比如这是市口啊,假设我们下边呢是一个地图, 地图是一个无缝的,你可以认为这地图是无限长的,一开始呢,地图在这个位置,你拖拖,拖到这个位置过后,拖完了,然后我马上要把它回到相应的这个位置, 懂了吧,画面都是一样的。好,就是要做这件事。好,这个代码呢,不用去深究啊,我大概给你说一下啥意思,就是一个简单的一个换算关系,你们去画个图,你们是都能理解啊,这个 extend 什么意思呢?这个 extend 呢,表示的是整个地图的坐标范围,好,打印看一下吧。 啊,你可以看到啊,它这个坐标范围,这是地图的最小横纵坐标,这是地图的最大横纵坐标,这地图范围这个范围是不变的啊,就是你无论怎么拖动,这个范围都是固定的啊,这是个莫卡托坐标系换算出来的坐标,它最小值就是这个,它换算出来的坐标是个正方形啊,最小的横纵坐标一样,最大的横纵坐标一样,这是固定的啊, 这是一个 cent, 那 么通过这个 cent 呢,它可以算出整个地图的宽度,然后这个 x 是 啥呢?这个 x 是 来自于 center 啊,就是目前的中心点的横坐标,因为我们只处理横向嘛。好,看一下这个 center 啊, center 就 不一样了,我们来看一下拖动,你看 center, 注意 x 的 值啊,我们就看 x 吧,我们就看一个 center 的 第一项就是打印这个 x, 看这个 x 是 不是在不断的增加。为了让朋友看的清楚了,我给他除以一千,因为他数字有点大,你可能看不太清楚,给他除以一个一千。好,来,再来一次啊,好,拖动,拖动。你看一下 x 的 值是不是越来越大?越来越大,为什么现在没有越来越大呢?因为我这里重设了啊,我把这个注了,注了就会发现出问题了,好,再来啊。 呃,你看这个值是不是越来越大,他是可以无限增加下去的啊,所以说呢,就是要重新设置中心点,就在做这个事,把这个中心点对应到前面那个地图的中心点 啊,怎么来设置?就是设置 center 啊,重新设置中心点,这里要需要一个换算啊,这个换算你们自己画自己去理解啊,我这里不给大家画了,这样子的话就没问题了啊,保存,你看一下,刷新好,这里拖动,拖动拖动,随便拖动,你看现在鼠标是不是依然正常了,对吧?然后点击,你看是不是都正常了? 好,于是呢,目前的事件就地图上的事件交互是不是就做完了?那剩下的事情就剩下一件事了,就是他的运动,你看这飞机是可以动的啊。对,点击看,这边放大啊,你看是不是一直在动啊?我们换一个中国的吧。呃,上面的地图呢,可能放大过后呢,由于这个瓦片图它就没有了。这好好, 你看一下这飞机是不是在动,对不对?那么飞机在动同时的路径是不是在更新?那么这就涉及到地图更新的问题了,那么地图更新了,我们下节课再说吧。

好,统一来说一下动态规划问题怎么解哈,我这么跟你说啊,就整个算法里边最难的也就是动态规划问题了,但是呢,所有的动态规划问题解他的思路呢,都是一个思路,就是你要想方设法去找到状态转移方程,只要你能够把这个找到了,那代码瞬间就出来了, 甚至你做多了,你会发现这个东西找到了大把都不用写了,有啥好写的,瞬间就可以出来。动态规划问题真正难在什么地方,就难在这个东西不好找,有些题呢好找,有些题就不好找,但是你至少可以下手了,你目标是这个东西,然后把这个东西找到过后再去说什么优化时间复杂度啊,空间复杂度啊,那些都是小事了啊,关键是找这个,那这个玩意到底是啥?咱们通过一个例子来说明哈, 这个例子呢,是一个中等难度的中规问题,他说啥意思呢?就是一个机器人啊,在一个多行多列的格子的左上角,他到达了格子的右下角,然后这个机器人呢,每一次呢可以向右移动,也可以向下移动啊,只能向右和下,请问这个机器人有多少条路径可以到达右下角? 这是个很庞大的,看上去很复杂的问题,是吧?那么这个时候呢,我们可以把这个问题呢来重新定义一下啊,比方说我们建立这么一个 d p 数组啊,它是个二维数组,那么我要给这个 d p 数组呢下个定义,这个数值表示啥意思?比方说 d p i g, 它表示啥意思呢?表示机器人从左上角到达 d i 行 d 界列一共有多少条路径?比方说 i 界定位到这个位置,那么 dpi 界表示什么意思?表示这个机器人从这里走到这里一共有多少条路径?那我们可以想一想啊,我们一旦把这个数组填完了,那这个数组的最后一项不就是这个位置吗?那这个最后一项的值不就是我们想要的结果吗?你好好捋一捋是不是? 好?如果说你这个东西捋清楚了,那我现在告诉你什么叫状态转移方程,就是在你这个 d p 定义的基础上,我要找到不同的 a 和界,他们之间的关系,你就要找这个,这东西找出来就结束了。比方说这个位置的路径数量,他跟其他格子的路径数量有什么样的一个关系? 你要去看这东西,那咱们来看一下吧。什么关系?你看要到达这个位置是不是只有两种情况,要么你从这里下来往下走,对吧?要么呢?你从这里过来往右走,是不是只有这两种情况?那是不是就意味着你到这个格子有多少条路径?再加上到这个格子有多少条路径,是不是就等于这个格子的路径数量? 然后你有十种办法到这,那你一定有十种办法到这,好理解吧?你再往下走一步呗,你有二十种路径到这,那一定有二十种路径到这,对吧?你往右走一步呗,是不?两个加起来就是他的总的路径数量, 那么对这个格子是不是如此?对其他格子是不是都同理呢?比方这个格子是不是还是一样的?你可以从这里下来,也可以从这里过来,是不是还是这两个格子加上这个格子的数量,是不是?于是状态转移方式就出来了?你看这还是个中等题啊,也没有那么难,是吧? i 键应该等于啥?是不等于左边啊?就是行不变列减一,它的数量加上右边,行减一,加上上边,对吧?行减一列不变,是不是?这就是状态转移方程。状态转移方程就是不同的结果之间他们存在着一个什么样的关系?这个方程只要一列出来,代码就结束了, 除非呢,你就要考虑一些特殊情况,是吧?表第一列的情况,就这一列的情况,这一列情况是不是全是一?为啥?表左上角到达,左上角只有一种情况,对吧?不动就完事了。左上角到达,这是不是只有一条路,对吧?往下走,左上角到达,这是不是也只有一条路连续往下走,对吧?说第一列全为一, 那么这一呢?是也是一样的,第一行是不全为一,对吧?机器人只有一条路线往这边走,是不是?所以呢,我们可以得到一种特殊情况啊,就是当 i 等于零的时候,或者是全为一的时候,是不是 dpi 就 为一,只有这条路线? 整个这个玩意就是状态转移方程。那这个状态转移方程做出来了,你可以用循环写,也可以用地轨写,随便你咋写都是对的。但我这里没说优化啊,优化的话是另外一个话题了。好,咱们来写一下啊。就是啊,像这种算法题啊,为什么一些大厂都喜欢考, 其实考的是啥呢?不是说你将来在工作当中正儿八经的去做一个机器人,要去走到右下角,不是这个意思啊。算法题考的到底是啥?考的是你的程序思维能力, 因为算法题里面没有什么第三方库,也没有什么框架,那些是考知识,知识是另外的考题,算法题就是用最基本的知识,能不能解决问题,也包括一些大堆的工具,但是你解决不了问题,那不扯淡吗?有啥用啊,这大嫂很看重这个,工具就那么多, 而且很多工具的大厂都是现成的,把一基础工具做完了,但是你能不能把手上的工具用好,来解决实际项目里边的一些困难?他考察这个,他说他为什么不直接把那个项目里边的东西拿来考察呢?哪怕一讲需求,可能一讲一天没有效率,就直接考算法就完事了。能不能用最基础的借贷吗?来解决问题不就考这个吗?这程序思维啊,永远是重中之重,而你要大幅度的提升这样的思维, 除了去刷各种算法题之外,还要好好来看我的大师课。大师课是完全免费的啊,来领取。完事了,在大师课里边,我会通过一些前端的实战效果案例,告诉同学们遇到一些具体的业务需求的时候,特别是一些下不了手的业务需求的时候,该怎么去分析和分解,以及如何来解除高质量的代码啊。当然,大师课里面还不仅仅是程序思维的培养啊, 包括了前端最重要,最核心,最能够直接影响你薪资高低的职业发展的知识,叫什么?浏览器的进程模型,渲染管线,这玩意可不是八国人啊,他对你的工作也好, 学习进阶知识也好,包括你的就业掌心也好,都起着直观重要的作用,还包括框架的原理,原版优化,都在大师课里边。你花几天时间啊,把它认认真真学完,它会给你整个职业生涯带来你意想不到的效果, 这种效果是可以长期持续下去的。所以说无论你是想高薪就业还是想再次提薪,大师课都是你的必修课。这课呢,目前是免费领啊,怎么领?在咱们账号主页,点击头像进入账号主页,点击提示领就完事了啊。好说回来啊,怎么写?你就照着这个玩意写就完事了啊。你现在需要一个什么二维数组是吧?建立这么一个 dp 数组,留一个二倍长度有多少啊?哪能弄长度啊,就是先第一个数再说 再循环呗,对吧?然后循环行, i 等于零, i 小 于 m, i 加加,再循环列, n 加加,对吧? 每循环一次行,是不是要往这个数组里边加一个数组,对吧?二位数组嘛,对吧?所以说我们这里呢,往里边加一个数组啊,好,然后呢?每一个单元格 dpi 介等于啥呢?是不?两种情况? dpi 介到底等于啥?这里第一种情况就 i 等于零,介等于零的情况啊。 如果说 i 等于零,或者是介等于零,那么这个玩意就为一 else, 否则的话就为啥?是不是就是这个东西复制粘贴过来? 好,最后呢?把这个输入的最后一下返回不就完了吗?写完了就这么点代码。所以你看好这个算法题啊,他往往代码并不复杂,关键是分析的思路很重要啊。我们把这个代码呢复制一下啊,然后给他整过来。好,然后一提交,那不就过了吗?啊?不过呢效率问题我这没考虑啊。你首先把它解出来再说,然后呢将来有机会再去聊效率问题吧。

有些同学用这个 ts 吧,就纯属一个心理安慰,所以说它标没标注呢?它好像也标注了,但是呢,用起来呢,跟别标注是一个样子的。呃,咱们来看个例子啊,这块类型该怎么来标注?就有这么一个 watch 函数,传入一个对象啊,它可以监听这个对象的属性变化, 它返回啥呢?返回一个新的 watch 啊,一个观察器,这是个典型的观察者模式,是吧?然后呢,观察器里边有个 on 方法,就可以监听当某一个属性变化的时候,比方说 age changed, 就 这个属性变化的时候。那么我要执行一个函数,对吧?它的旧的值是啥?新的值是啥? 那么至于说这个 word 函数如何去实现,那个不重要,现在我们聊的是这个类型咋标注好?首先是个 word 函数,怎么标注类型?有些朋友就这样标注,他不是接受的对象吗? 对吧?那我就给他标明一个对象的参数,他返回的不是个观察器吗?那我就给他返回一个观察器。好,这个观察器呢,上面标注一下,他就提供一个 on 方法, 里面传两个东西,一个是事件名字,对吧?他是个字不串。然后呢,有一个回调函数,旧的值也不知道是啥,新的值也不知道是啥,全是 n 例。标注完没?你说他标注完没?肯定标注完了,是吧?但是这样的标注跟没标注差不多,你这里随便乱写怎么样呢?我就乱写了,有这个事件吗?没有这个事件啊,哪有这个属性啊,他也不报错,对吧?很多人觉得 t s 很 烦, 因为它会增加你的开发成本。这个确实是啊, t s 本来就会增加开发成本,这是一定的,但它 t s 增加开发成本有没有好处呢?它有好处,它换的是啥呢?换的是使用成本和维护成本。就这笔生意划不划算,那就看你的项目了。 你的项目如果说是一个小型项目,就那么三五个人,你说你标注的那么细致,其实起不到啥作用,甚至你使用 t s, 我 就觉得是值得商榷的,没必要, 小的项目哪有那么高的维护成本,而且也没有什么公共库账里写是吧?很少,基本上都是一些业务型的代发临时写一下对吧,把这块的功能实现就完事了。所以说呢,即便使用 ts 啊,它类型标注呢,也不需要那么细致。这也是为什么很多同学对 ts 不是 很感冒的原因,因为他大部分时候都接触的是一些小型项目, 但是在大型项目里边就完全不一样了。大型项目里边你要写很多的公共库的,如果说这些库你不把它标注好的话,它的使用成本是很高的,它使用上经常会出问题,而且大型项目的维护成本也很高,所以说 ts 真正的威力是要在大型项目里边才能体现出来。因此这得出一个什么结论 啊?是不是对于 t s 这门技术,你可以在平时工作当中的时候简单处理,甚至不写都行,但是呢,你不能不具备做细致类型标注的能力,这个能力你是必须要具备的,否则的话,你是永远不可能接触到大型项目的。 说远了哈,说回来,这玩意该怎么标注,怎么标注呢?首先我们就看到这个问题发生在这个 on 方法,是吧?这个 on 方法,这个事件名字,它可不能直接是一个字母串,它得是一个啥呢?它得是这么一个东西,啥啥啥 changed, 对 吧?这是它的事件名字,那么这个啥啥啥是不是有可能会变化?后边的后缀是不变的,对吧?前面这个东西是可以变化的, 怎么变化?是不是可以拼接一个类型计算?比方说它可以是一个 x, 也可以是一个啥,也可以是个 a 级,要么就是 x 嵌进,要么就是 a 级嵌进的。那你看,这样子,写了过后,我们下边就不能随便写了,随便写报错的,你只能是啥?你只能要么是 a 级嵌进,要么是 x 嵌进,对吧?是不是要好很多了?但是吧,你正儿八经这样写的话也不行。为啥呢?这个 watch 是 通用的呀, 你不能定死了,它一定是观察了这个对象啊,对不对?它来自于一个对象的所有字段名。 那我们一步一步推导呗,而这个对象在哪呢?这里没有这个对象,没有的话怎么办?你通过翻行给我传过来呗。因此你要用这个 watch 的 时候,是不是要给它传递这个翻行 t? 你 是观察哪个对象,对吧?我才能好做类型标注。那这里有这个 t 吗?这里没这个 t。 是 不是又一次来这个翻行给他一次传过去,对不对?你传入这个 object 是 什么类型,那我这个翻行就是什么类型,那我就去观察它,对吧?一步步推导过来,那然后问题又在这了,这里为什么会报错呢?这是个典型的 t, 也是错误啊,这种错误应该是很多人都遇到过吧, 应该知道怎么解决吧。什么错误啊?你在做什么?做字母串拼接。那就必须要保证这一块得是一个字母串吧,但它这里保证不了。为啥呢?因为某一个对象的字段它是不是有可能是 symbol 啊,对 吧?对象的字段它有可能是字母串类型,有可能是字母,字母的话这里就没法拼接了。所以说应该怎么样?是不应该加上一个字母串做一个类型交叉,对吧?这个很典型吧,就是说比如说一个字母串连上类型 a b, 然后加上一个字母,然后呢给一个字母串来做交叉,得到的结果是啥?就是 a 和 b, 对 吧? 什么就没了,非常典型的一个操作,是吧。啊,像我讲的这些小知识啊,小点啊,如果说符合你的胃口的话,我强烈建议你啊,一定要来看看我的大师课。大师课跟短视频一样啊,是完全免费的。那你去晚上了?因为短视频呢,他是讲不了一些成体系的核心知识的,就像我刚才说的很多东西吧,你可能现在工作当中是用不到的,但是你将来你要求职 党心到达更高阶的岗位是需要这些核心知识的,你没有这些东西的话,你永远只能在目前的工作上待着,你即便跳槽也只跳了一个差不多的工作。之前团队三个人,现在团队四个人,有啥区别呢?没啥区别。之前做一个 o a a, 现在做一个 c i m, 有区别吗?没啥区别。之前写表格,现在写表格,有区别吗?没区别,这样子的话到后边年龄大了是会遇到问题的哈,因为你干的活所有人都能干,除了卷,薪资卷,加班,我不知道卷啥了。因此你要往上走,往更高的岗位上去,求一个更好的职业发展。不愿意在底层待着了,那就必须要去学习那些大型项目里边要用到的核心知识。那那些知识在哪?都在大师课里边,你 花几天时间把大师课认认真真学完,你不用我说哈,你自己都能感觉到你自己又能打了,这课程是能够带你在职业生涯发展上上一个台阶的课程哈, 这么好的东西,可千万千万不要错过了。关键这个课呢?目前免费领啊,怎么领?在咱们账号主页,点击头像进入账号主页给你提示,领就完事了啊。好,我写到目前这个情况的话来看一下,至少第一个参数搞定了,你看是不是就这个几个属性,你不能乱写的啊?你这个可以,但是你乱写的话肯定不行,怕跑错人。 那么接下来就第二个问题了,就第二个函数,你不能写 n 啊。那这里应该是啥呢?那就看你监听的是哪个属性了。比方说你监听的是属性 k, 那 这里就应该写啥呢? t k 是 吧,那这里是不是一样的来自于这个对象的某一个属性的类型?那现在问题是,我现在没有这个属性了,没有这个属性怎么办?是不是又靠反型了?那么现在问题是,这个反型写到哪个位置呢? 是写到这里这个位置,还是写到 on 这个位置?那就想一想这个逻辑呗,什么时候能确定你监听的是哪个属性?是在这里确定的吗? 是吧,这里我只是创建一个观察器,是在哪里确定的?是不在 on? 这里确定的。哦,我现在要监控的是这个 first name, 哦,我现在监控的是这个 six。 哦,我现在监控的是这个 age, 是 不是在 on 的 时候确定你监听的是哪个属性?是不是?所以 k 应该写到哪?是不是应该写到这儿?而这个 k 是 不是有约束,跟这个 t 是 什么关系? k 必须是啥?是不是? k 必须得是一个?这个 是不是它来自于 t 的 某一个字段,那么也就意味着啥?这里是不就应该是 k 了?比方说你监听的是 age change 的, 那么监听的这个 k 是 啥? k 就是 age, 看到没,它就推导出来了,然后这里写的是什么? six change, 那 么这里监听的是啥?就是 six, 那 么后边的 old value 和 new value 的 类型是不是就应该是 six 的 类型,对吧?那就写完了,你看现在就很舒服了。 我这里第一个参数不能乱写,要报错的,我只能写它写正确的字。比方说写这个 age change, 那 么后边的回调函数是不是变成 number 了?然后如果说这里监听的是 啊, first name changed, 那 么后边的类型是啊,就是字母 c 啊,这才是一个好的标注。你说代码多吗?其实也不多,也就是一二三四五六六行。那如果说这是个通用函数的话,就会为以后的维护也好,使用也好,省非常非常多的事儿,就很难出错了。

这节课来看事件监听,事件监听就是监听某个事件,当这个事件被触发的时候,执行一系列操作,可以通过下面这个方法来添加事件监听。之前我们使用过事件,比如点击事件 都已经实现了触发事件,调用函数执行一些操作,为什么还有事件监听?我们来看代码,给这个按钮定义一个点击事件, 我们一直都是这样写的,然后电用函数,这函数里边是改变这个标题的颜色,改为蓝色看效果, 改变颜色,标题变成了蓝色,我们直接显示的在这里面定义了他的点击事件,我们也可以通过实验监听来实验这样的效果, 把它给去掉。 当进入到这个页面加载完成的时候,给这个按钮添加监听,添加阿罗的事件 定义这个方法 来解释一下,当页面加载完成之后,调用这个函数,这函数里边获取这一个按钮,给这个按钮添加事件监听。这个方法第一个参数是事件的类型,这个是点击事件。第二个参数是一个函数, 就是触发这个点击事件的时候要调用的函数,这里边的内容就和刚才一样了,这就相当于一个初始化的过程, 把元素的这些事件都给预备好。如果一个页面比较复杂,里边很多元素都需要有事件,那么都可以在这函数里面给他写上来看效果, 点击改变了他的颜色,和刚才效果是一样的。使用时间。监听的好处,一个是把 gs 代码从 h 贴面中分离出来了,写在这里更完整易读,一个是这样写比较灵活,而不是把它写死在这里面。 既然有添加的方法,而且也有删除监听的方法。好了,这节课就到这里。


大家好,我是机器人,今天我们来看一下怎么使用 http 模块来收发和监听数据。这里我们使用一个开放服务, 也就是 d w e t 点 i o。 这个网站给我们提供了几个有用的接口。还有接口的使用说明。比如这个是发送数据的接口,下面这个是获取数据的接口。 这个是监听数据的接口。监听数据是使用长连接分块传输实现的。每当服务器收到新消息, 就会给监听的设备发送数据。但是每次常连接的时间有限,所以常连接断开后需要立即发出新的连接。在这个页面我们可以看到有在线 的测试工具,这也方便了我们调试接口。 这里可以看到监听数据的接口,不能在这里测试,不过可以用 crow 命令进行查看。这次我们只用到了这三个接口。 这里我已经整理好了这杰克的功能,还是点亮指示灯,不过这次在任何地方都可以使用。手机控制, 不再依赖局域网,也不需要知道单片机的 ip 地址,只要我们用手机打开一个网页就可以控制了。首先是入口文件,设备启动后,首先连接网络,当网络连接成功,就会自动调用监 监听方法。这里会首先设置一下指示灯的最后状态。之后就是调用独一的模块的监听方法,开始监听数据。当接口收到数据变化, 就会触发回调函数,然后根据返回值来设置指示灯的状态。 bate 模块我们简单的封装了一下,就是根据参数给指定的接口发送 get 请求,并且给参数进行了简单的加密处理,毕竟是开放的服务, 数据是很容易被别人获取到的,发送数据也是一样的。加密用的是 bottle, 对应的解密用的是 atop。 当然小伙伴们也可以使用其他加密算法。我们这里的重点是发送和接收数据,就不做复杂的加密了。这个是监听数据的接口,这个接口是常 连接的,数据也是分段返回的,每次数据返回都会调用我们设置的函数。这样就实现了单片机部分的代码。我们还需要一个网页来发送控制命令。这里我只用了一个 svg 图片,当点击这个图片的时候,就会切换指示灯的状态。 当刚打开页面的时候,也会获取当前的状态。其实就是用 fashion 方法给指定的接口发送请求。页面的运行效果是这个样的, 当点击灯泡的时候,就会改变灯泡的颜色,并且给指定的接口发送控制命令。当单片机收到控制命令,就会改变指示灯的状态。当我们修改配置并把代码写入设备后,就可以用这个网页进行控制了。自己有服务器的小 伙伴可以把这个页面放到自己的服务器上,没有服务器的小伙伴也可以把页面发到微信里,那样就可以在手机上控制了。现在来看一下最终效果吧, 感觉还不错。今天就到这里吧,我们下期再见。

好,来看这道题啊,那么如何优化 gs 文件的执行时间?执行时间呢?它是提升咱们应用性能的一个环节啊,那有哪些点给大家推荐几个方法?比如说减少不必要的计算。一 要计算,那我们可以提前退出,是吧?提前退出,比如说,呃,我们尽早返回已知的结果,避免不必要的计算,那我们也可以使用。哎,长量,使用长量, 嗯,就是把重复使用的表达式复制给常量,减少重复的计算。第二个呢就是代码简化和重做, 那比如说我们避免这个全局查找,避免全局查找,对吧?局部变量呢?它要比全局变量访问的更快。还有就是减少作用域的查找啊,减少作用域的作用域的查找 查找,嗯,尽量使用局部变量,而不是嵌套,呃,比较深的这个作用力,知道吧?第三个呢就是事件处理优化,事件事件处理优化,那比如说我们可以做这个事件委托处理,对吧? 我委托事件处理,那我们使用委事件委托呢,来减少事件监听器的绑定数量,也可以防抖截流啊。防抖截流。 那第四点呢,就是 don't 操作的流放, don't 操作的流放,你比如说我们批量更新,对吧?哎,把多次 don't 操作呢合并成一次,减少回流和融汇。那我们这里呢就使用到的就是 document fragment 啊, document, 呃, fragment fragment, ok, 用它。 第五个呢就是循环右环,循环循环右环,那也就是减少循环次数,减少循环次数。然后第六个呢就是算法优化, 算法优化我们要选择合适的数据处理算法,哎,针对特定情况选择最优的一个算法也可以。呃,要也注意这个,避免这个低规,知道吧?尽可能是使用迭代来替代这个低规啊。 通过这些策略呢,我们就可以减少 g s 的 这个执行时间了,提高应用的整体一个性能。 ok, 这个呢,就是这道题的理解。

各位学前端的同学,天天做 c r u d, 感觉没前途,没法提长心。那你可以试试 sheet g s 这种工具。假如我们有一个配置活动的 c r u d, 每次创建活动你都要填写一大堆表单,这玩意实在是太烦人了。虽然它不难,但是它多呀, 光写表单项就得写一会儿,吭叽吭叽,实现了之后,运营还得抱怨说不好用,为啥你配置也得配半天啊,这摆明就是吃力不讨好嘛。那有什么办法可以稍微减少开发时间,同时又能大幅减少运营配置的时间呢? 这个时候啊,就需要用到 shift js 这个工具。简单说啊,它就是将表格转换成其他格式,比如我们常用的 json。 因为运营一般在设计活动的时候,它们本身也会有一个表格,用来记录活动配置和活动数据。而当我们有了这个工具之后,运营就可以少一次填写表单的时间。尤其是对于这种大量表单项和一些批处理的逻辑都非常有效。 比如我们在这里选择上传表格,打开之后,它就会将表格里的数据自动填写到你的表单里啊。当然,我们也可以直接解析成 jason 之后发出去,不需要再做这一项, 那这样他不就大幅减少了运营的配置时间吗?至于说这个工具怎么用,那就不多介绍了,有文档和 ai, 使用上基本没啥难度。哎,那这个东西跟掌心有什么关系呢? 你提掌心总得做出点成绩吧?那什么是成绩?要么节省开发时间,要么节省其他部门的使用时间。只要你能节省时间,那在提掌心的时候就可以成为你的依据。


前几天有个学弟面试回来,一脸怀疑人生地问我哥, javascript 里的 date 到底怎么讲才算讲明白?我就会 knew 一下当前时间。我听完笑了。 很多人对 date 的 理解,真的就停留在现在几点。但在我眼里, date 更像是 javascript 事件里的时间管理局局长。所有和时间有关的事,打卡倒计时,活动开始结束,订单过期,通通都要找他签字。你每次创建一个 date, 本质上是在问系统从幺九七零 年一月一日那一刻,到现在过去了多少毫秒。这个 ds 柱就叫时间戳,它像一条时间河流的里程数,所有时间计算都是基于他在做加减法。 很多人第一次被坑,是发现月份居然从零开始算。是的,一月是零,二月是。那一刻你会怀疑人生,但慢慢你会发现,程序世界有自己的规则,你只能理解他,而不是和他争论。 date 其实不是孤单的存在,它继承自 object, 也就是说,它天生就带着一些基础能力,比如转成四幅串,或者转成数字。当它变成数字的时候,就是时间戳。当它变成四幅串的时候,就是我们人类能读懂的时间样子。 但原始输出往往很直男,一长串英文看着就头大。于是我们就会做格式化,让时间变得优雅一点,只显示日期,或者只显示时间,或者变成二零二六年三月二日 十点三十五分二十秒这种更符合业务场景的格式。很多项目里,这一步几乎是必做的,因为用户体验就藏在这些细节里。 更有意思的是,你可以把一个时间拆开,取出年份、月份、日期、小时分钟秒,就像把一只钟表一块块拆开研究,你也可以反过来修改它,把时间往前调往后调, 注意,他是会直接改原对象的,这一点很多人都会踩坑。真正让我对 data 产生敬畏是一次线上事故。那是一个秒杀活动,前端显示活动已经结束,但服务器其实还没结束,差了三秒钟。 就是这三秒,让用户疯狂刷新,让客服电话爆炸。那一刻,我才意识到前端时间是不可靠的。真正权威的是服务器时间, 时间不一致,业务就会混乱。从那以后,我对 date 再也不敢轻视。它不仅是一个对象,更是系统秩序的一部分。时间差计算、倒计时、缓存、过期判断,本质上都是在和 d s 打交道。所以,如果你现在对 date 的理解还停留在获取当前时间,那真的太可惜了。它背后是时间错的数学逻辑,是组建拆分的细节规则,是格式化的用户体验,也是分布式系统里时间一致性的思考。