js网页设计
用JavaScript写网页,网页最容易被忽略的设计一点是:它先是一门语言,然后才是网页“网页技术”。很多初学者一上来就学jQuery、设计学React,网页结果连闭包和作用域都说不清楚。设计我见过一个做了三年前端的网页人,被问到“事件循环里微任务和宏任务的设计执行顺序”时,支支吾吾答不上来。网页这不是设计个别现象。 浏览器给JS提供了一个宿主环境,网页这个环境里最重要的设计两个东西是BOM和DOM。BOM管的网页是浏览器窗口本身,比如 我刚开始写JS的时候,特别喜欢用 事件处理是另一个分水岭。绑定点击事件谁都会,但事件流有几个阶段?捕获、目标、冒泡,三个阶段。默认情况下,事件在冒泡阶段触发。如果你在父元素上绑了监听器,子元素被点击时,父元素的监听器也会执行。这个机制叫事件委托,用好了能省很多事。比如一个列表有100个window.location、设计window.history、网页setTimeout这些。DOM管的是页面里的元素,document.getElementById、querySelector都属于它。很多人把这两者混在一起记,用的时候能跑通就行,但一旦遇到跨域、iframe通信、history路由这些问题,脑子里就没有清晰的边界。document.write。那会儿觉得这方法真方便,直接往页面里塞内容。后来才知道,在页面加载完成后调用它,整个文档会被重写。有一次线上页面白屏,排查了半天,就是某个老代码在异步回调里调了document.write。这个教训让我明白:DOM操作不是“能跑就行”,你得知道它在什么时机、什么上下文里执行。上就行。但很多人不知道
event.target和event.currentTarget的区别,写出来的代码虽然能跑,逻辑却是错的。
异步这块,回调函数是绕不开的。setTimeout、fetch、addEventListener,全都是回调。回调写多了会嵌套,嵌套深了就成了“回调地狱”。Promise解决了嵌套的问题,但.then链写长了也不好看。async/await是语法糖,底层还是Promise,用起来像同步代码,但执行顺序仍然是异步的。我见过有人写了async function,然后在里面用await去等一个setTimeout,结果发现拿不到想要的结果。原因很简单:setTimeout不返回Promise,await一个非Promise值会立即resolve,根本不会等待。
说到具体案例,我拿一个搜索框的防抖来举例。用户每输入一个字符就发一次请求,这显然不合理。防抖的思路是:设定一个延迟,每次输入都重置计时器,只有用户停止输入超过延迟时间才真正发请求。代码大概长这样:
function debounce(fn, delay) { let timer = null; return function(...args) { clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), delay); }; } 这段代码里有个细节:fn.apply(this, args)。为什么要用apply?因为返回的函数被调用时,this指向可能变了,直接调用fn(args)会丢失上下文。这个点很多教程不讲,但实际项目里踩过坑的人都会记得。
模块化也值得说两句。ES6之前,JS没有原生模块系统,大家用IIFE模拟,或者用CommonJS、AMD。现在import和export是标准,但浏览器里用type="module"加载的脚本,默认是严格模式,而且顶层this是undefined。这些细节不写清楚,代码放到浏览器里就是各种报错。
最后提一下调试。console.log是最常用的,但很多人不知道console.table、console.time、console.trace。断点调试比打日志高效得多,Chrome DevTools的Sources面板可以给代码打断点,查看调用栈、作用域链、闭包变量。学会用调试工具,比背API有用得多。
JS网页设计这件事,说到底就是理解浏览器怎么解析和执行你的代码。API记不住可以查,但执行机制搞不清楚,写出来的东西就是碰运气。
-
上一篇
-
下一篇