<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ 小生方勤 - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ 小生方勤 - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 08:28:41 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/author/xiao/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 几个常见的 JavaScript 数组方法 ]]>
                </title>
                <description>
                    <![CDATA[ 关于 JavaScript 数组一类的面试题目时不时出现，那么它的考点在哪里呢？ 其实这类题的目的很清楚，即考察：  * 数组方法的基础知识  * 数值转换方法的基础知识 也就是考察基础知识的扎实程度，换句话说这是一道基础题。 map()、filter()、reduce() 等数组方法 说明一下：map()、filter() 是 ES5 为数组定义的迭代方法， reduce() 是 ES5 为数组定义的归并方法。这些方法并不是 ES6 新增的语法（之前在一场面试中，面试官很肯定的说这是 ES6 新增的方法）。  * 你可以在 《JavaScript 高级程序设计-第三版》 96-97 页中看到明确的说明。 语法:   array.filter(callback[,thisObject]);   // array.map(callback[,thisObject]);   // array.reduce(callback[,initialValue]) 都不会改变原始数组。 参数：   callback：要对每个数组元素执行的回调函数。  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/javascript-array-method/</link>
                <guid isPermaLink="false">5f9179945f583f0565090b62</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 数组 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 前端开发 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 小生方勤 ]]>
                </dc:creator>
                <pubDate>Thu, 22 Oct 2020 12:22:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2020/10/tudor-baciu-vc3iVL_znJ8-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>关于 JavaScript 数组一类的面试题目时不时出现，那么它的考点在哪里呢？</p><p>其实这类题的目的很清楚，即考察：</p><ul><li>数组方法的基础知识</li><li>数值转换方法的基础知识</li></ul><p>也就是考察<strong>基础知识的扎实程度</strong>，换句话说这是一道基础题。</p><h2 id="map-filter-reduce-">map()、filter()、reduce() 等数组方法</h2><p>说明一下：<code>map()、filter()</code> 是 ES5 为数组定义的迭代方法， <code>reduce()</code> 是 ES5 为数组定义的归并方法。这些方法并不是 ES6 新增的语法（之前在一场面试中，面试官很肯定的说这是 ES6 新增的方法）。</p><ul><li>你可以在 《JavaScript 高级程序设计-第三版》 96-97 页中看到明确的说明。</li></ul><p><strong>语法:</strong></p><pre><code>  array.filter(callback[,thisObject]);
  // array.map(callback[,thisObject]);
  // array.reduce(callback[,initialValue])</code></pre><p>都不会改变原始数组。</p><p><strong>参数：</strong></p><pre><code>  callback：要对每个数组元素执行的回调函数。
  thisObject：在执行回调函数时定义的 this 对象(没有传递或者为 null，将会使用全局对象)。
  // initialValue: 作为第一次调用 callback 函数时的第一个参数的值。
 </code></pre><h3 id="map-">map()</h3><p>对原数组中的每个元素<strong>按顺序</strong>执行一次指定的函数（即 callback），callback 每次执行后的返回值（包括 undefined）组合起来形成一个新数组。</p><p>回调函数可以有三个参数：当前元素，当前元素的索引 <code>[可选]</code> 和当前的数组对象 <code>[可选]</code> 。</p><h3 id="filter-">filter()</h3><p>对原数组中的每个元素执行一次指定的函数（即 callback），并且创建一个新的数组，该数组元素是所有回调函数执行时返回值为 true 的原数组元素。</p><p>回调函数可以有三个参数：当前元素，当前元素的索引 <code>[可选]</code> 和当前的数组对象 <code>[可选]</code> 。</p><h3 id="reduce-">reduce()</h3><p>对原数组中的每个元素执行一次指定的函数（即 callback），返回最后一次回调返回值。</p><p>回调函数可以有四个参数：累计器，当前元素，当前元素的索引 <code>[可选]</code> 和当前的数组对象 <code>[可选]</code> 。</p><p><strong>提醒</strong>：reduce() 区别于 map()/filter() 的地方就在回调函数的第一个参数 - accumulator：累计器。</p><h2 id="parseint-parsefloat-">parseInt()、parseFloat() 两个数值转换方法</h2><h3 id="parseint-">parseInt 语法</h3><pre><code>  parseInt(string, radix)  </code></pre><p>将一个字符串 string 转换为 radix（值默认为 10） 进制的整数，radix 为介于 2-36 之间的数。</p><p>注意：string 将看作是一个数的 n 进制表示，<strong>返回的值为十进制</strong>。</p><p><strong>返回值：</strong></p><ul><li>如果被解析参数的第一个字符无法被转化成数值类型，则返回 <strong>NaN</strong></li><li>如果 radix 小于 2 或者大于 36，则返回 <strong>NaN</strong></li></ul><p><strong>在 radix 为 undefined，或者 radix 为 0 或者没有指定的情况下，JavaScript 作如下处理：</strong></p><ul><li>如果字符串 string 以"0x"或者"0X"开头, 则 radix 是 16 (16进制).</li><li>如果字符串 string 以"0"开头, radix 是8（八进制）或者10（十进制），具体值由实现环境决定。ECMAScript 5 规定使用 10，但是并不是所有的浏览器都遵循这个规定。因此，永远都要明确给出 radix 参数的值</li><li>如果字符串 string 以其它任何值开头，则 radix 是 10 (十进制)。</li></ul><h3 id="parsefloat-">parseFloat 语法</h3><pre><code>  parseFloat(string)</code></pre><p>只有一个参数，用作将给定值解析成浮点数（如果给定值不能被转换成数值，则会返回 <strong>NaN</strong>）。</p><h2 id="-arr-filter-parseint-">解释 arr.filter(parseInt)</h2><p>其实以上的过程就很好地解析了这个问题，此类问题只要理解基本方法的传参就不会出错了，而且不需要强记<code>['1', '2', '3'].map(parseInt)</code>的结果。</p><pre><code>let arr = [2,0,11,10];
arr.filter(parseInt);

// arr.map(parseInt); // [2, NaN, 3, 3]</code></pre><p>1、首先 arr 的每个元素执行一次 parseInt，传入 parseInt 的参数就是<strong>当前元素和当前元素的索引</strong>。</p><p>2、经历如下过程：</p><pre><code>- parseInt(2,0)   // 结果为 2，转成 Boolean 为 true
- parseInt(0,1)   // 结果为 NaN，转成 Boolean 为 false
- parseInt(11,2)  // 结果为 3，转成 Boolean 为 true
- parseInt(10,3)  // 结果为 3，转成 Boolean 为 true</code></pre><p>所以最后返回 <code>[2, 11, 10]</code>。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Canvas 动画的性能优化实践 ]]>
                </title>
                <description>
                    <![CDATA[ 去年圣诞节有一个下雪的背景动画的需求，我在实现这个动画的过程中加深了对 canvas 动画的一些了解，在这里我仅是抛砖引玉分享一下，欢迎各位批评指正。 代码已上传至 GitHub 【https://github.com/wanqihua/blog】，感兴趣的可以 clone 代码到本地运行。 入题 需求给出的 UI 样式如下： UI 的需求是雪花下落的方向有点倾斜角度，每片雪花的下落速度不一样但要保持在一个范围内。 需求了解的差不多就开始实现这个效果（在看这篇文章之前你需要对 canvas 的一些基本 API 了解）。 drawImage drawImage 可传入 9 个参数，上图中的 5 个参数是比较常用的，另外几个参数是拿来剪切图片的。 > 直接使用 drawImage 来剪切图片，其性能不会太好，建议先将需要使用的部分用一个离屏 canvas 保存起来，需要用到的时候直接使用即可。 requestAnimationFrame requestAnimationFrame 相对于 setinterval 处理动画有以下几个优势：  1. 经过浏览器优化，动画更流畅   ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/canvas-animation-performance-optimization-practice/</link>
                <guid isPermaLink="false">5df04c50ca1efa04e196a949</guid>
                
                <dc:creator>
                    <![CDATA[ 小生方勤 ]]>
                </dc:creator>
                <pubDate>Sat, 01 Aug 2020 02:09:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2020/08/web-design-2906159_960_720.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>去年圣诞节有一个下雪的背景动画的需求，我在实现这个动画的过程中加深了对 canvas 动画的一些了解，在这里我仅是抛砖引玉分享一下，欢迎各位批评指正。</p><p>代码已上传至 GitHub 【https://github.com/wanqihua/blog】，感兴趣的可以 clone 代码到本地运行。</p><h2 id="-">入题</h2><p>需求给出的 UI 样式如下：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/12/image-15.png" class="kg-image" alt="image-15" width="1080" height="2012" loading="lazy"></figure><p>UI 的需求是雪花下落的方向有点倾斜角度，每片雪花的下落速度不一样但要保持在一个范围内。</p><p>需求了解的差不多就开始实现这个效果（在看这篇文章之前你需要对 canvas 的一些基本 API 了解）。</p><h3 id="drawimage">drawImage</h3><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/12/image-16.png" class="kg-image" alt="image-16" width="741" height="249" loading="lazy"></figure><p><code>drawImage</code> 可传入 9 个参数，上图中的 5 个参数是比较常用的，另外几个参数是拿来剪切图片的。</p><blockquote>直接使用 <code>drawImage</code> 来剪切图片，其性能不会太好，建议先将需要使用的部分用一个离屏 <code>canvas</code> 保存起来，需要用到的时候直接使用即可。</blockquote><h3 id="requestanimationframe">requestAnimationFrame</h3><p><code>requestAnimationFrame</code> 相对于 <code>setinterval</code> 处理动画有以下几个优势：</p><ol><li>经过浏览器优化，动画更流畅</li><li>窗口没激活时，动画将停止，节省计算资源</li><li>更省电，尤其是对移动终端</li></ol><p>这个 API 不需要传入动画间隔时间，这个方法会告诉浏览器以最佳的方式进行动画重绘。</p><p>由于兼容性问题，可以使用以下方法对 <code>requestAnimationFrame</code> 进行重写：</p><pre><code>window.requestAnimationFrame = (function(){
        return  window.requestAnimationFrame       || 
                window.webkitRequestAnimationFrame || 
                window.mozRequestAnimationFrame    || 
                window.oRequestAnimationFrame      || 
                window.msRequestAnimationFrame     || 
                function (callback) {
                    window.setTimeout(callback, 1000 / 60); 
                };
    })();
</code></pre><p>对于其他 API 烦请查阅文档。</p><h2 id="--1">第一次尝试</h2><p>有一个大概想法后就开心的开始写代码了，基本思路就是使用 <code>requestAnimationFrame</code> 来刷新 <code>canvas</code> 画板。</p><p>由于雪花不规则，所以雪花是 UI 提供的图片，既然是图片我们就需要先将图片预加载好，要不然在转换图片的时候很可能影响性能。</p><p>使用的预加载方法如下：</p><pre><code>function preloadImg(srcArr){
    if(srcArr instanceof Array){
        for(let i = 0; i &lt; srcArr.length; i++){
            let oImg = new Image();
            oImg.src = srcArr[i];
        }
    }
}
</code></pre><p>前前后后写了一个下午，算是写好了，在手机上查看的效果发现很是卡顿。100 片雪花 <code>FPS</code> 尽然平均才 40 多。而且在某些机型会出现都懂得情况。</p><p>要是产品看到这个效果，恐怕是又要召集相关人员开相关会议了。这么卡顿肯定是写了些开销大的代码，于是乎需要第二次尝试。</p><p>晚上还是需要按时下班的。不过下班回家后也不能闲着，开始找相关的资料，以便第二天快速的完成。</p><h2 id="--2">第二次尝试前的准备</h2><p>经过一个晚上的查找学习，大概知道了以下几个优化 <code>canvas</code> 性能的方法：</p><h3 id="1-">1. 使用多层画布绘制复杂场景</h3><p>分层的目的是降低完全不必要的渲染性能开销。</p><blockquote>即：将变化频率高、幅度大的部分和变化频率小、幅度小的部分分成两个或两个以上的 <code>canvas</code> 对象。也就是说生成多个 <code>canvas</code> 实例，把它们重叠放置，每个 <code>Canvas</code> 使用不同的 <code>z-index</code> 来定义堆叠的次序。</blockquote><pre><code>&lt;canvas style="position: absolute; z-index: 0"&gt;&lt;/canvas&gt;
&lt;canvas style="position: absolute; z-index: 1"&gt;&lt;/canvas&gt;
// js 代码
</code></pre><h3 id="2-requestanimationframe-">2. 使用 requestAnimationFrame 制作动画</h3><p>上面有提到。</p><h3 id="3-clearrect">3. 清除画布尽量使用 clearRect</h3><p>一般情况下的性能：<code>clearRect</code> &gt; <code>fillRect</code> &gt; <code>canvas.width=canvas.width;</code></p><h3 id="4-">4. 使用离屏绘制进行预渲染</h3><p>当时用 <code>drawImage</code> 绘制同样的一块区域：</p><ol><li>若数据源（图片、canvas）和 <code>canvas</code> 画板的尺寸相仿，那么性能会比较好；</li><li>若数据源只是大图上的一部分，那么性能就会比较差；因为每一次绘制还包含了裁剪工作。</li></ol><blockquote>第二种情况我们就可以先把待绘制的区域裁剪好，保存在一个离屏的 <code>canvas</code> 对象中。在绘制每一帧的时候，在将这个对象绘制到 <code>canvas</code> 画板中。</blockquote><p><code>drawImage</code> 方法的第一个参数不仅可以接收 <code>Image</code> 对象，也可以接收另一个 <code>Canvas</code> 对象。而且，使用 <code>Canvas</code> 对象绘制的开销与使用 <code>Image</code> 对象的开销几乎完全一致。</p><p>当每一帧需要调用的对象需要多次调用 <code>canvasAPI</code> 时，我们也可以使用离屏绘制进行预渲染的方式来提高性能。</p><p>即：</p><pre><code>let cacheCanvas = document.createElement("canvas");
let cacheCtx = this.cacheCanvas.getContext("2d");

cacheCtx.save();
cacheCtx.lineWidth = 1;
for(let i = 1;i &lt; 40; i++){
    cacheCtx.beginPath();
    cacheCtx.strokeStyle = this.color[i];
    cacheCtx.arc(this.r , this.r , i , 0 , 2*Math.PI);
    cacheCtx.stroke();
}
this.cacheCtx.restore();

// 在绘制每一帧的时候，绘制这个图形
context.drawImage(cacheCtx, x, y);
</code></pre><blockquote><code>cacheCtx</code> 的宽高尽量设置成实际使用的宽高，否则过多空白区域也会造成性能的损耗。</blockquote><p>下图显示了使用离屏绘制进行预渲染技术所带来的性能改善情况：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/12/image-17.png" class="kg-image" alt="image-17" width="700" height="219" loading="lazy"></figure><h3 id="5-canvasapi-">5. 尽量少调用 <code>canvasAPI</code> ，尽可能集中绘制</h3><p>如下代码：</p><pre><code>for (var i = 0; i &lt; points.length - 1; i++) {
    var p1 = points[i];
    var p2 = points[i + 1];
    context.beginPath();
    context.moveTo(p1.x, p1.y);
    context.lineTo(p2.x, p2.y);
    context.stroke();
} 
</code></pre><p>可以改成：</p><pre><code>context.beginPath();
for (var i = 0; i &lt; points.length - 1; i++) {
    var p1 = points[i];
    var p2 = points[i + 1];
    context.moveTo(p1.x, p1.y);
    context.lineTo(p2.x, p2.y);
}
context.stroke();
</code></pre><blockquote>tips: 写粒子效果时，可以使用方形替代圆形，因为粒子小，所以方和原看上去差不多。有人问为什么？很容易理解，画一个圆需要三个步骤：先 <code>beginPath</code>，然后用 <code>arc</code> 画弧，再用 <code>fill</code>。而画方只需要一个 <code>fillRect</code>。当粒子对象达一定数量时性能差距就会显示出来了。</blockquote><h3 id="6-">6. 像素级别操作尽量避免浮点运算</h3><blockquote>进行 <code>canvas</code> 动画绘制时，若坐标是浮点数，可能会出现 <code>CSSSub-pixel</code> 的问题.也就是会自动将浮点数值四舍五入转为整数，在动画的过程中就可能出现抖动的情况，同时也可能让元素的边缘出现抗锯齿失真情况。</blockquote><p>虽然 javascript 提供了一些取整方法，像 <code>Math.floor</code>， <code>Math.ceil</code>， <code>parseInt</code>，但 <code>parseInt</code>这个方法做了一些额外的工作（比如检测数据是不是有效的数值、先将参数转换成了字符串等），所以，直接用 <code>parseInt</code> 的话相对来说比较消耗性能。<br></p><p>可以直接用以下巧妙的方法进行取整：</p><pre><code>function getInt(num){
    var rounded;
    rounded = (0.5 + num) | 0;
    return rounded;
}
</code></pre><blockquote>另 for 循环的数组效率是最高的，具体感兴趣的可以自行实验。</blockquote><h2 id="--3">第二次尝试</h2><p>通过昨天晚上的查阅，对这个动画做了以下几点优化:</p><ol><li>使用离屏绘制进行预渲染</li><li>减少部分 API 的使用</li><li>浮点数取整</li><li>缓存变量</li><li>使用 for 循环，替代 forEach</li><li>将整体代码使用原型链方式改写了一遍</li></ol><p>方案写好了就开始愉快的写代码了。</p><p>200 片雪花的时候 <code>FPS</code> 基本稳定在 60，而且抖动的情况也没了；<br>增加到 1000 片的时候， <code>FPS</code> 还是基本稳定在 60；<br>增加到 1500 片的时候，稍微有点零星的卡帧；<br>增加到 2000 片的时候，开始卡顿。</p><p>这说明这个动画还是没有优化好，还有优化空间，请各位大佬不吝指教。</p><blockquote>推荐使用 <code>stats.js</code> 插件，这个插件可以显示动画运行时的 FPS。</blockquote><h3 id="--4">主要代码</h3><pre><code>let snowBox = function () {
    let canvasEl = document.getElementById("snowFall");
    let ctx = canvasEl.getContext('2d');
    canvasEl.width = window.innerWidth;
    canvasEl.height = window.innerHeight;
    let lineList = []; // 雪的容器
    let snow = function () {
        let _this = this;
        _this.cacheCanvas = document.createElement("canvas");
        _this.cacheCtx = _this.cacheCanvas.getContext("2d");
        _this.cacheCanvas.width = 10;
        _this.cacheCanvas.height = 10;
        _this.speed = [1, 1.5, 2][Math.floor(Math.random()*3)];                // 雪花下落的三种速度，便于取整
        _this.posx = Math.round(Math.random() * canvasEl.width);               // 雪花x坐标
        _this.posy = Math.round(Math.random() * canvasEl.height);              // 雪花y坐标
        _this.img = `./img/snow_(${Math.ceil(Math.random() * 9)}).png`;        // img
        _this.w = _this.getInt(5 + Math.random() * 6);
        _this.h = _this.getInt(5 + Math.random() * 6);
        _this.cacheSnow();
    };

    snow.prototype = {
        cacheSnow: function () {
            let _this = this;
            // _this.cacheCtx.save();
            let img = new Image();   // 创建img元素
            img.src = _this.img;
            _this.cacheCtx.drawImage(img, 0, 0, _this.w, _this.h);
            // _this.cacheCtx.restore();
        },
        fall: function () {
            let _this = this;
            if (_this.posy &gt; canvasEl.height + 5) {
                _this.posy = _this.getInt(0 - _this.h);
                _this.posx = _this.getInt(canvasEl.width * Math.random());
            }
            if (_this.posx &gt; canvasEl.width + 5) {
                _this.posx = _this.getInt(0 - _this.w);
                _this.posy = _this.getInt(canvasEl.height * Math.random());
            }
            // 如果雪花在可视区域
            if (_this.posy &lt;= canvasEl.height || _this.posx &lt;= canvasEl.width) {
                _this.posy = _this.posy + _this.speed;
                _this.posx = _this.posx + _this.speed * .5;
            }
            _this.paint();
        },
        paint: function () {
            ctx.drawImage(this.cacheCanvas, this.posx, this.posy)
        },
        getInt: function(num){
            let rounded;
            rounded = (0.5 + num) | 0;
            return rounded;
        }
    };

    let control;
    control = {
        start: function (num) {
            for (let i = 0; i &lt; num; i++) {
                let s = new snow();
                lineList.push(s);
            }
            (function loop() {
                ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
                for (let i = 0; i &lt; num; i++) {
                    lineList[i].fall();
                }
                requestAnimationFrame(loop)
            })();
        }
    };
    return control;
}();

window.onload = function(){
    snowBox.start(2000)
};
</code></pre><p>建议从 GitHub clone 代码到本地运行。</p><h2 id="--5">后话</h2><p>这篇文章虽然说是关于 canvas 动画的性能优化。一些大佬也已经看出，其他方面的性能优化方案和这个大抵相同，无非是：</p><ol><li>减少 API 的使用</li><li><strong>使用缓存（重点）</strong></li><li>合并频繁使用的 API</li><li>避免使用高耗能的 API</li><li>用 webWorker 来处理一些比较耗时的计算</li><li>……</li></ol><p>希望这篇文章可以在性能优化方面给你作一个参考。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ F5 同 Ctrl+F5 的区别你可了解 ]]>
                </title>
                <description>
                    <![CDATA[ 代码修改后，告知产品 UI 问题已修复，让她本地验证一下。几分钟过后，产品说问题还可以复现。而后去产品那才发现她一直使用 F5 刷新页面。我告诉她 F5 和  Ctrl+F5 的区别后，也就有了这篇文章。 其实 F5 和 Ctrl+F5 使用的频率是很高的，可是在使用的时候有没有想过 F5 和 Ctrl+F5 的区别是什么？这篇文章会将 F5 和 Ctrl+F5  刷新页面的原理讲清楚。通过这篇小文，即便是对浏览器缓存机制加深一点点的认知，也是有所裨益的。 入题 下图是我们第一次打开掘金的 Network 界面，由于是第一次打开，所以全部资源是从服务器请求的， Status 都是 200。 接下来我们按一下 F5，看看效果； 发现静态资源的 Size 都是 fromdisk cache；说明此时的静态资源是从缓存中取的。具体为什么 Size 是 fromdisk cache  我先按下不表。我先来说说 size 选项的 4 种情况。 size 选项的 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/the-difference-between-f5-and-ctrl-f5/</link>
                <guid isPermaLink="false">5e35321aca1efa04e196b011</guid>
                
                <dc:creator>
                    <![CDATA[ 小生方勤 ]]>
                </dc:creator>
                <pubDate>Sun, 02 Feb 2020 02:30:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/photo-1580411788412-8d5fe9d849c8.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>代码修改后，告知产品 UI 问题已修复，让她本地验证一下。几分钟过后，产品说问题还可以复现。而后去产品那才发现她一直使用 <code>F5</code> 刷新页面。我告诉她 <code>F5</code> 和 <code>Ctrl+F5</code> 的区别后，也就有了这篇文章。</p><p>其实 <code>F5</code> 和 <code>Ctrl+F5</code> 使用的频率是很高的，可是在使用的时候有没有想过 <code>F5</code> 和 <code>Ctrl+F5</code> 的区别是什么？这篇文章会将 <code>F5</code> 和 <code>Ctrl+F5</code> 刷新页面的原理讲清楚。通过这篇小文，即便是对浏览器缓存机制加深一点点的认知，也是有所裨益的。</p><h2 id="-">入题</h2><p>下图是我们第一次打开掘金的 <code>Network</code> 界面，由于是第一次打开，所以全部资源是从服务器请求的， <code>Status</code> 都是 <code>200</code>。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-5.png" class="kg-image" alt="image-5" width="1080" height="600" loading="lazy"></figure><p>接下来我们按一下 <code>F5</code>，看看效果；</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-9.png" class="kg-image" alt="image-9" width="1080" height="616" loading="lazy"></figure><p>发现静态资源的 <code>Size</code> 都是 <code>fromdisk cache</code>；说明此时的静态资源是从缓存中取的。具体为什么 <code>Size</code> 是 <code>fromdisk cache</code> 我先按下不表。我先来说说 <code>size</code> 选项的 <code>4</code> 种情况。</p><h3 id="size-4-">size 选项的 4 种情况</h3><ol><li>资源的大小</li><li>from disk cache</li><li>from memory cache</li><li>from ServiceWorker</li></ol><h4 id="from-memory-cache">from memory cache</h4><p>表示此资源是取自内存，不会请求服务器。已经加载过该资源且缓存在内存当中；关闭该页面此资源就被内存释放掉了，再次打开相同页面时不会出现 <code>frommemory cache</code> 的情况。</p><h4 id="from-disk-cache">from disk cache</h4><p>表示此资源是取自磁盘，不会请求服务器。已经在之前的某个时间加载过该资源，但是此资源不会随着该页面的关闭而释放掉，因为是存在硬盘当中的，下次打开仍会 <code>fromdisk cache</code>。</p><h4 id="--1">资源本身大小数值</h4><p>当 <code>http</code> 状态为 <code>200</code> 是实实在在从浏览器获取的资源，当 <code>http</code> 状态为 <code>304</code> 时该数字是与服务端通信报文的大小，并不是该资源本身的大小，该资源是从本地获取的。</p><h4 id="from-serviceworker">from ServiceWorker</h4><p>表示此资源是取自 <code>fromServiceWorker</code>。</p><p><strong>现在我们再按下 <code>Ctrl+F5</code>，看看效果。</strong></p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-10.png" class="kg-image" alt="image-10" width="1080" height="570" loading="lazy"></figure><p>发现 <code>Size</code> 显示的又是资源自身的大小，说明 <code>Ctrl+F5</code> 后的资源又是重新从服务器中请求得到的。</p><h2 id="f5-ctrl-f5-">F5 同 Ctrl+F5 的区别</h2><p>为什么 <code>F5</code> 后请求的是缓存，而 <code>Ctrl+F5</code> 就重新请求资源呢？答案就是这两种方式发送的请求头不一样（不同的浏览器发送的请求头也有一些区别）。</p><h3 id="f5">F5</h3><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-11.png" class="kg-image" alt="image-11" width="1080" height="353" loading="lazy"></figure><p>在 <code>chrome</code> 浏览器中按 <code>F5</code> 后，看到资源的请求头中有 <code>provisional headers are show</code> 字样。这是为什么呢？</p><blockquote>原因：未与服务端正确通信。该文件是从缓存中获取的并未进行通信，所以详细标头并不会显示。强缓存 <code>fromdisk cache</code> 或者 <code>frommemory cache</code> ，都不会正确的显示请求头。</blockquote><p>下面看看按 <code>F5</code> 后在 <code>firefox</code> 浏览器中的表现。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-12.png" class="kg-image" alt="image-12" width="1080" height="467" loading="lazy"></figure><p>从图中可以看出返回的状态码是 <code>304NotModified</code>。</p><blockquote>这是因为按 <code>F5</code> 进行页面刷新时请求头会添加 <code>If-Modify-Since</code> 字段，如果资源未过期，命中缓存，服务器就直接返回 <code>304</code> 状态码，客户端直接使用本地的资源。</blockquote><p>可以看出 <code>chrome</code> 和 <code>firefox</code> 在按下 <code>F5</code> 后，其内部使用的缓存机制不同。<code>firefox</code> 使用的是协商缓存，而 <code>chrome</code> 使用的是强缓存。</p><h3 id="ctrl-f5">Ctrl+F5</h3><p>我们还是先看看在 <code>chrome</code> 中 <code>Ctrl+F5</code> 的表现。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-1.png" class="kg-image" alt="image-1" width="1080" height="484" loading="lazy"></figure><p>我们发现在请求头中多了两个 <code>Cache-Control:no-cache，Pragma:no-cache</code> 参数，这两个参数什么意思呢？</p><blockquote>在请求头中的 <code>Cache-Control:no-cache</code> 表示客户端不接受本地缓存的资源，需要到源服务器进行资源请求，其实可以使用缓存服务器的资源，不过需要到源服务器进行验证，验证通过就可以将缓存服务器的资源返回给客户端。</blockquote><p>那么在 <code>Firefox</code> 中的表现是怎样的呢？</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image-13.png" class="kg-image" alt="image-13" width="1080" height="507" loading="lazy"></figure><p>请求头中同样多了两个 <code>Cache-Control:no-cache，Pragma:no-cache</code> 参数。</p><p>可以看出 <code>chrome</code> 和 <code>Firefox</code> 在按下 <code>Ctrl+F5</code> 后，都不会使用本地缓存，并且对缓存服务器的资源会再验证。</p><p>写到这里差不多就把 <code>F5</code> 同 <code>Ctrl+F5</code> 的缓存原理讲的差不多了。不过每个浏览器它们在实现同一个动作的时候，总是会有差异，不过在业界内 <code>chrome</code> 的缓存优化机制是做的最好的。这也是为什么我们在使用 <code>chrome</code> 开发或者是浏览网站的时候体验都不错的原因。</p><p>读完 <code>F5</code> 同 <code>Ctrl+F5</code> 刷新页面的原理，其实你也把强缓存和协商缓存的区别也复习了一遍。</p><h3 id="--2">补充</h3><p>我们可以通过勾选 <code>Network</code> 面板中的 <code>Disablecache</code> 选项，这样当你按 <code>F5</code> 的时候，也是直接请求服务器资源的效果。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/02/image.png" class="kg-image" alt="image" width="752" height="189" loading="lazy"></figure> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 关于前端学习路线的一些建议 ]]>
                </title>
                <description>
                    <![CDATA[ 前言 这几个月几乎每天都会有朋友加我微信，而他们问的最多的问题就是 —— 前端技术现在如此繁杂，我到底应该如何学习 。这个话题太大了，几句话回答不好；也由于这个问题确实困扰了很多前端开发人员，所以我也就着手系统的输出这篇文章。 > 虽然这篇文章花了很长时间，肯定也有其局限性；希望各位不吝指出。 入题 我们俨然能感受到前端岗位现在已经发展成了最重要的研发岗位之一，所以对我们提出的要求也就越来越高。所以我们需要学的也就不仅仅只是  CSS&HTML&JavaScript  了。但这三大件一直都是前端的根本，这一点从未改变。而这三大件中 JavaScript  又是重中之重。 接下来我会结合我的一点经验，给出前端学习路线的一些具体建议。 目录  * 三大件学习  * 库工具  * 前端框架（ MVVM ）的学习  * 浏览器 & 计算机基础  * 前端工程化  * 性能优化  * Nodejs  * 数据结构和算法  * 依葫芦画瓢 三大件学习 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/map-of-learning-front-end/</link>
                <guid isPermaLink="false">5d84347bfbfdee429dc5fd0a</guid>
                
                <dc:creator>
                    <![CDATA[ 小生方勤 ]]>
                </dc:creator>
                <pubDate>Fri, 20 Sep 2019 02:19:08 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/photo-1568815611917-e8126507d510.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="-">前言</h2><p>这几个月几乎每天都会有朋友加我微信，而他们问的最多的问题就是 —— <strong>前端技术现在如此繁杂，我到底应该如何学习</strong>。这个话题太大了，几句话回答不好；也由于这个问题确实困扰了很多前端开发人员，所以我也就着手系统的输出这篇文章。</p><blockquote>虽然这篇文章花了很长时间，肯定也有其局限性；希望各位不吝指出。</blockquote><h2 id="--1">入题</h2><p>我们俨然能感受到前端岗位现在已经发展成了最重要的研发岗位之一，所以对我们提出的要求也就越来越高。所以我们需要学的也就不仅仅只是 <code>CSS&amp;HTML&amp;JavaScript</code> 了。但这三大件一直都是前端的根本，这一点从未改变。而这三大件中 <code>JavaScript</code> 又是重中之重。</p><p>接下来我会结合我的一点经验，给出前端学习路线的一些具体建议。</p><h2 id="--2">目录</h2><ul><li>三大件学习</li><li>库工具</li><li>前端框架（ MVVM ）的学习</li><li>浏览器 &amp; 计算机基础</li><li>前端工程化</li><li>性能优化</li><li>Nodejs</li><li>数据结构和算法</li><li>依葫芦画瓢</li></ul><h2 id="--3">三大件学习</h2><p>现在每年依旧有很多初级入门的前端开发。所以对初入门的朋友也给出一点意见。</p><p>刚入门的朋友，我觉得不应该一开始就学习像 <code>Vue、TypeScript、Webpack</code> 等知识。应该把重点放在 <code>CSS&amp;HTML&amp;JavaScript</code> 基础知识的学习上。</p><h3 id="css-html">CSS &amp; HTML</h3><p>对于刚入门的朋友我依旧建议先将 <code>CSS(3)&amp;HTML(5)</code> 的知识点认真学习一遍。学习的途中最好是学习完一部分就自己在敲一遍代码，加深自己的记忆。</p><p>当然如果你愿意，建议你可以先仿一个网站的静态页面（掘金、知乎等都可以），有一些属性就可以了解他实际的实现场景。</p><blockquote>当然刚开始敲代码的时候还是不要过分依赖自动补全功能，一开始就使用自动补全对你记忆一些属性时没有帮助的；踏实点学习，日后会有回报的。</blockquote><p><strong>关于 CSS(3) 你需要了解的一些知识点</strong></p><ul><li>盒模型（标准 &amp; IE ）</li><li>flex、float、Normal Flow 等的理解</li><li>CSS 常用选择器</li><li>行内、内部、外部样式的区别</li><li>CSS 层叠规则</li><li>BFC 与 IFC 的了解</li><li>CSS3 的 transform、transition、animation 等属性的运用了解</li><li>响应式布局的理解</li><li>……</li></ul><blockquote>CSS 说容易也容易，说复杂也复杂；因为 CSS 总是能给你意外的惊喜。</blockquote><p><strong>HTML(5) 你需要了解的一些知识点</strong></p><p>说到 HTML 我想有很多人是 <code>div</code> 一把梭。因为 <code>div</code> 用的爽，不用担心默认样式。</p><blockquote>有人说 HTML 语义化的优点很多，比如清晰的页面结构、有利于 SEO、便于团队开发和维护；这些我都承认，不过我还是喜欢 <code>div</code> 一把梭。</blockquote><ul><li>HTML 语义化( 不是很理解为什么面试总会问 )</li><li>canvas</li><li>本地存储（ localStorage、sessionStorage、cookie 的理解 ）</li><li>video 和 audio 的使用</li><li>应用缓存( cache manifest )</li><li>……</li></ul><p><strong>JavaScript</strong></p><p><code>JavaScript</code> 一直都是我们前端的基石，一定程度上 <code>JavaScript</code> 的理解深度决定了你的发展。所以一定要用心学习。</p><blockquote>现在很多人一看到闭包、原型链、作用域链、继承之类的文章都是直接跳过，你现在可以自问一下你的确理解这些基础的知识点吗？</blockquote><p><code>JavaScript</code> 的基础知识点确实很多，所以《JavaScript 高级程序设计》 写了 700 多页；不过当你 JS 基础扎实后，你会发现你在学习框架、亦或是学习框架源码的时候会轻松许多。</p><p><strong>JavaScript（ES6+） 你需要了解的一些知识点</strong></p><ul><li>类型转换</li><li>this</li><li>作用域（作用域链）</li><li>原型链以及继承</li><li>闭包的理解</li><li>动态作用域和词法作用域</li><li>JavaScript 执行机制</li><li>promise &amp; async</li><li>……</li></ul><p>上面说的 <code>CSS&amp;HTML&amp;JavaScript</code> 的基础知识点并不需要你一入门就全部都理解透彻；有些虽然是基础，但却也有它的难度。就算是高级也不敢说自己全都掌握了，有句话说的挺好 —— 书读百遍、其义自见。</p><p>我们第一遍学习不可能尽懂，到最少可以给我留下一个印象。过一段时间再学习这块知识点的时候，你肯定会有一个全新的理解。学习只一个需要一直在线的任务，重复的学习可以帮助你保持持续的竞争力。</p><p>我先声明一点，我并没有说其他技术不需要去学习，只不过初入门最好重点是先将基础夯实。</p><p>其实三大件的学习不需要花费多少时间，有基础的大概 3 个月就可以大致的看一遍。是否真的理解这是后话，不过已经算是入门了。</p><p><strong>CSS &amp; HTML &amp; JavaScript 推荐书籍/网站</strong></p><ol><li>_ W3C 的 CSS&amp;HTML 网络教程</li><li>《CSS 权威指南》</li><li>《CSS 揭秘》</li><li>《JavaScript 高级程序设计》</li><li>《你不知道的 JavaScript》上卷</li><li>_ ECMAScript 6 入门</li></ol><blockquote>HTML 不知道推荐什么书。我个人觉得看教程和动手实践就基本没什问题。</blockquote><p>接下来我们就可以学习一些工具类的库了。</p><h3 id="--4">库工具</h3><p>对于库工具而言我们常用的有 JQuery、underScore、zepto、Moment 等</p><ul><li>JQuery: 降低开发者操作 DOM 的复杂度</li><li>UnderScore: 提供实用的函数</li><li>Zepto: JQuery 的简化版</li><li>Moment: 日期和时间操作库</li></ul><p>这些库给我们提供了很大的便利，省去了我们编写相关方法的时间，同时也是我们的程序更加稳健 —— 我们自己写的方法很可能在某些情况下就出 bug 了。</p><blockquote>当然对于这些库我们不仅仅只是去了解 API，我们需要去学习它的源码。看看如果自己写相关方法的话是不是也想到了这种方式，这些库工具是也是一个很好的学习工具，我们不应该忽略。</blockquote><ul><li>比如让你自己实现节流函数，你会如何实现。</li><li>过滤对象应该如何实现</li><li>……</li></ul><blockquote>这种问题的答案不就在 Underscore 源码里面吗？</blockquote><p>我们在学习库工具的时候，必定是需要回头看 JavaScript 基础的；这也就进一步夯实了基础。</p><h2 id="-mvvm-">前端框架（ MVVM ）的学习</h2><p>当下最火的框架想必一定是 React 和 Vue，如果 JQuery 的存在是是我们更加方便的操作 DOM,那么现在 MVVM 框架则是让我们从手动更新 DOM 的繁杂操作中解放出来。</p><p>至于 React 和 Vue 该学习哪一个，更多的还是看当下公司使用的是哪一个（也不是必然）。对于 Vue(React) 该如何使用其实不用多久就能上手，我们更应该关心的是他们背后的设计思想和实现原理。</p><h3 id="--5">一些问题</h3><ul><li>响应式的基本原理是什么</li><li>发布订阅模式的理解</li><li>Virtual DOM 的理解</li><li>前端路由的实现原理</li><li>nextTick / setState 的实现原理</li><li>diff 算法</li><li>单页面应用（SPA）的原理和优缺点</li><li>……</li></ul><blockquote>我们对于框架的 API 使用没必要花太多时间，应该多研究他们背后的设计思想和实现原理。</blockquote><h3 id="vue-react-">Vue 和 React 我该选择哪一个？</h3><p>对于这个问题相比很多人都有困扰（有些人两个都学，也就没有这个困扰），这个问题已经有很多人回答了。但我还是觉得不是非要选择哪一个才是政治正确，选择你需要的。</p><p>感兴趣的可以看看这篇文章：<br>React or Vue: Which Javascript UI Library Should You Be Using?</p><p>以下是提炼的文中观点：</p><p><strong>Vue的优势是：</strong></p><ul><li>模板和渲染函数的弹性选择</li><li>简单的语法和项目配置</li><li>更快的渲染速度和更小的体积</li></ul><p><strong>React的优势是：</strong></p><ul><li>更适合大型应用和更好的可测试性</li><li>同时适用于 Web 端和原生 App</li><li>更大的生态系统，更多的支持和好用的工具</li></ul><h3 id="vue-">Vue 相关资料</h3><p>对于框架的一些学习资料我个人更倾向于推荐官方文档，有很多问题官方文档已经说得很清楚了。市面上有些书籍也就是对官方文档进行了一个扩写（不排除有精良之作）。</p><ol><li>Vue 官网 &amp; Vue Router 官网 &amp; Vuex 官网</li><li>剖析 Vue.js 内部运行机制 掘金小册</li><li>vue 技术揭秘</li></ol><h2 id="--6">浏览器 &amp; 计算机基础</h2><p>如果你希望能能快速进阶到高级工程师，那么对于浏览器 &amp; 计算机基础的知识你就必要又有一定的掌握。因为这能让你更好的理解前端。</p><p>浏览器一直是 JavaScript 最重要的宿主环境，所以我们必须去了解 JavaScript 在浏览器中是如何执行的。</p><p>我们前端开发接触最多的应该就是浏览器了，记得工作第一年最头痛的就是处理 IE 的兼容问题。工作中出现的很多问题都和浏览器有关，所以我觉得了解浏览器工作原理是非常有必要的。</p><h3 id="--7">为何要学习浏览器工作原理？</h3><ol><li>准确评估 Web 开发项目的可行性</li><li>从更高维度审视页面</li><li>解决面试中遇到的绝大部分浏览器问题</li></ol><h3 id="--8">计算机基础</h3><p>对于计算机基础我们需要做到大体了解，这样的话我们对整体的流程会有一个大概的把握。在实际开发过程中不会过于被动。</p><h3 id="--9">需要了解的一些知识点</h3><ul><li>浏览器缓存机制</li><li>浏览器中 JavaScript 的执行机制</li><li>页面渲染原理</li><li>浏览器安全问题</li><li>浏览器为什么会跨域</li><li>如何系统的优化页面</li><li>HTTP 与 HTTPS 的区别</li><li>TCP/IP 协议</li><li>三次握手和四次挥手</li><li>CDN 的作用和原理</li><li>正向代理与反向代理的特点</li><li>……</li></ul><p>这里仅仅列出了一部分知识点，如果想全面的学习可以看下面推荐的资料。</p><h3 id="--10">浏览器 &amp; 网络基础推荐书籍/资料</h3><ol><li>《浏览器工作原理与实践 》专栏</li><li>《图解 HTTP》</li><li>《网络是怎样连接的》</li></ol><h2 id="--11">前端工程化</h2><p>从事前端稍微久一点的开发就一定会有这个感受 —— 前端开发越来越工程化，越来越复杂。</p><p>对于前端开发来说，现在前端要做的不只是切页面调接口这么简单，我们需要了解的技术无疑更加广泛。</p><h3 id="--12">前端工程化的一点浅见</h3><p>由于项目的复杂度越来越高，前端需要做的工作就越来越繁重。当项目复杂就会产生许多问题，比如：</p><ul><li>如何进行高效的多人协作？</li><li>如何保证项目的可维护性？</li><li>如何提高项目的开发质量？</li><li>如何降低项目生产的风险？</li></ul><blockquote>前端工程化细分的话我觉得可以分成模块化、组件化、规范化三个方向。或者说一切能提升前端开发效率，提高前端应用质量的手段和工具都是前端工程化的实践。</blockquote><h4 id="--13"><strong>模块化</strong></h4><ul><li>JavaScript 模块化</li><li>CSS 模块化</li><li>资源模块化</li></ul><p><strong>组件化</strong></p><p>从 UI 拆分下来的每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元，我们称之为组件。</p><p>也就是将复杂页面按功能拆分成多个独立的组件。</p><p><strong>规范化</strong></p><ul><li>编码规范</li><li>接口规范</li><li>git 使用规范</li><li>CodeReview</li><li>UI 元素规范</li></ul><p><strong>前端工程化一些知识点</strong></p><ul><li>理解 Babel、ESLint、webpack 等工具在项目中的作用</li><li>Babel 的核心原理</li><li>Webpack 的编译原理、构建流程、热更新原理</li><li>nginx 的基本理解</li><li>理解 Git 的工作流程</li><li>Mock 的意义及优点</li></ul><h2 id="--14">性能优化</h2><p>提起性能优化，大家最先想到的是什么？我最先想到的是一道面试题：</p><blockquote>从输入 URL 到页面加载完成的具体过程</blockquote><p>因为从直观层面来看，我们前端需要优化的步骤基本都在这个加载工程当中。</p><p>性能优化现在对于前端来说已经是必不可少的技能了，当然现在有些所谓的性能优化的技巧现在都成为了一种需要遵从的规范。</p><p>我们需要关注两个方向的性能优化：</p><ol><li>运行时的优化</li><li>开发时的优化</li></ol><h3 id="--15">性能优化一些知识点</h3><ul><li>前端性能衡量指标、性能监控（performance,LightHouse）</li><li>常见的性能优化方案有哪些</li><li>SSR 方案的性能优化</li><li>Webpack 的性能优化方案</li><li>React、Vue 等框架使用性能优化方案</li><li>网络层面的优化方案</li><li>页面渲染层面的优化方案</li><li>白屏的优化方案</li><li>……</li></ul><h3 id="--16">推荐资料</h3><ul><li>《大型网站性能优化实战》</li></ul><h2 id="nodejs">Nodejs</h2><p>我们知道由于 Nodejs 的出现，前端开发出现了一个新的高潮。JS 开始可以涉及后端领域，JS 的可能性更大了。</p><h3 id="nodejs-">Nodejs 一些知识点</h3><ul><li>Nodejs 在应用程序中的作用</li><li>Express 和 Koa 的区别</li><li>Nodejs 的底层运行原理、和浏览器的异同</li><li>Nodejs 非阻塞机制的实现原理</li><li>……</li></ul><h2 id="--17">数据结构和算法</h2><p>这一点我也比较薄弱，就不展开了。关于这部分你可以刷 leetcode。</p><p>另外推一本书《学习 JavaScript 数据结构与算法》（第三版）</p><h2 id="--18">依葫芦画瓢</h2><p>我们在项目开发的过程中可以接触到很多优秀的库工具或者是 UI 库，如 lodash、underscore、moment、element-ui、antd design 等。</p><p>我们可能自己设计不出来这么优秀的工具，但是我们完全可以依葫芦画瓢自己按着这些工具写一遍，你就会发现里面有很多不可思议的技巧、优秀的思想。</p><p>依葫芦画瓢对学习来说也是一个非常有用的技巧。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 11 个 CSS 知识搭配 11 个 JS 特性 ]]>
                </title>
                <description>
                    <![CDATA[ 前言 这篇文章我会介绍 11 个在开发过程中经常遇到的 CSS 相关知识点，以及 11 个有趣亦实用的 JavaScript 特性。 这些都是我在日常开发中总结而来，想必于你也是有或多或少的帮助。 文中的代码发布在 GitHub [https://github.com/wanqihua/blog]，想了解的朋友可以前往。 11 个常见的 CSS 知识点 声明，这里也包含了部分 CSS 预处理器知识，愿各位不要纠结于此。 1. position:fixed 降级问题 不知道曾经的你是不是遇到吸顶效果，就是使用 position:fixed 这个属性。其实如果其父元素中有使用 transform， fixed 的效果会降级为  absolute。 解决方案： 既然会降级为 absolute 效果，我们该怎么解决这个问题呢？我们就改考虑什么情况下 fixed 和 absolute 的表现效果会是一样的。 即当使用 fixed 的直接父元素的高度和屏幕的高度相同时 fixed 和 absolute 的表现效果会是一样的。 如果这个直接父级内的元素存在滚动的情况，那就加上 ove ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/commonly-used-css-knowledge-and-interesting-js-features/</link>
                <guid isPermaLink="false">5d708f08fbfdee429dc5fab2</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 小生方勤 ]]>
                </dc:creator>
                <pubDate>Thu, 05 Sep 2019 04:51:07 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/photo-1567517094718-7081a01877fc.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="-">前言</h2><p>这篇文章我会介绍 11 个在开发过程中经常遇到的 CSS 相关知识点，以及 11 个有趣亦实用的 JavaScript 特性。</p><p>这些都是我在日常开发中总结而来，想必于你也是有或多或少的帮助。</p><p>文中的代码发布在 <a href="https://github.com/wanqihua/blog">GitHub</a>，想了解的朋友可以前往。</p><h2 id="11-css-">11 个常见的 CSS 知识点</h2><p>声明，这里也包含了部分 CSS 预处理器知识，愿各位不要纠结于此。</p><h3 id="1-position-fixed-">1. position:fixed 降级问题</h3><p>不知道曾经的你是不是遇到吸顶效果，就是使用 <code>position:fixed</code> 这个属性。其实如果其父元素中有使用 <code>transform</code>， <code>fixed</code> 的效果会降级为 <code>absolute</code>。</p><p><strong>解决方案：</strong></p><p>既然会降级为 <code>absolute</code> 效果，我们该怎么解决这个问题呢？我们就改考虑什么情况下 <code>fixed</code> 和 <code>absolute</code> 的表现效果会是一样的。</p><p>即当使用 <code>fixed</code> 的直接父元素的高度和屏幕的高度相同时 <code>fixed</code> 和 <code>absolute</code> 的表现效果会是一样的。</p><p>如果这个直接父级内的元素存在滚动的情况，那就加上 <code>overflow-y:auto</code>。</p><h3 id="2-">2. 合理使用变量</h3><p>一般设计稿中的某一类的文字（元素）都是用相同的字体大小、颜色、行高等样式属性，所以这些值我们不必每次都重复写，因为当 UI 更新设计方案，你需要改的地方就很多了。这些重复使用的值我们完全可以存放在变量里面。</p><p>Sass 和 Less 稍微有点区别：</p><pre><code class="language-JavaScript">// sass
$direction: left;
// less
@direction: left;</code></pre><p>当然 CSS 原生也是存在变量的，使用规则如下：</p><p>变量定义的语法是：--；// *为变量名称。<br>变量使用的语法是：var()；</p><ol><li>无论是变量的定义和使用只能在声明块 {} 里面</li><li>CSS 变量字符限制为：[0-9]、[a-zA-Z]、_、-、中文和韩文等。</li></ol><pre><code class="language-JavaScript">:root {
--blue_color: #3388ff;
--main_bgcolor: #fafafa;
--font_size_12: 12px;
--font_size_14: 14px;
--color: 20px;
}
.div1{
background-color: var(--main_bgcolor);
font-size: var(--font_size_12);
}</code></pre><h3 id="3-mixin-">3. 使用 Mixin 归类重复样式</h3><p>和重复变量一样，重复的样式也可以归类。我觉得优秀的代码其中有一条肯定是代码的复用性强。</p><p>之前我们写 CSS 的时候，也会将一些重复使用的代码放在一个 class 中，这样的确达到了一定的复用性，不过最后的效果可能就是在一个元素里面放了很多 class，如下图：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image.png" class="kg-image" alt="image" width="536" height="135" loading="lazy"></figure><p>这样下一个接手得人难免会有点迷糊，而且这样会造成样式越来越难修改。</p><p>这个时候，mixin( 可以理解成 class 中的 class )就能发挥它的作用了。</p><p>这是一个描述性文字的样式：</p><pre><code class="language-JavaScript">.font-description {
.font-des-style(24px,#fff,1.5em);
.line-camp(2);
}

// less
/* 多行显示 */
.line-camp( @clamp:2 ) {
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: @clamp;
-webkit-box-orient: vertical;
}

.font-des-style( @fontSize, @color, @lineHeight, @textAlign:left ) {
font-size: @fontSize;
color: @color;
line-height: @lineHeight;
text-align: @textAlign;
}</code></pre><p>这只是一个简单的例子，我们可以把可复用的样式放在 mixin 中，这样接手项目的人只需要熟悉你写的 mixin.less 就可以开始迭代需求了</p><h3 id="4-1px-">4. 1px 方案</h3><p>做过移动端需求的前端肯定是避免不了处理 <code>1px</code> 细线问题，这个问题的原因就是 UI 对页面美观度的要求越来越高（不要和我说这是 retina 屏的问题）。</p><p>代码如下：</p><pre><code class="language-JavaScript">.min-device-pixel-ratio(@scale2, @scale3) {
@media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
transform: @scale2;
}
@media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3) {
transform: @scale3;
}
}

.border-1px(@color: #DDD, @radius: 2PX, @style: solid) {
&amp;::before {
content: "";
pointer-events: none;
display: block;
position: absolute;
left: 0;
top: 0;
transform-origin: 0 0;
border: 1PX @style @color;
border-radius: @radius;
box-sizing: border-box;
width: 100%;
height: 100%;
@media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
width: 200%;
height: 200%;
border-radius: @radius * 2;
transform: scale(.5);
}
@media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3) {
width: 300%;
height: 300%;
border-radius: @radius * 3;
transform: scale(.33);
}
}
}

.border-top-1px(@color: #DDD, @style: solid) {
&amp;::before {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
border-top: 1Px @style @color;
transform-origin: 0 0;
.min-device-pixel-ratio(scaleY(.5), scaleY(.33));
}
}</code></pre><h3 id="5-css">5. 内联首屏关键 CSS</h3><p>性能优化中有一个重要的指标 —— 首次有效绘制（FMP），即指页面的首要内容（primary content）出现在屏幕上的时间。这一指标影响用户看到页面前所需等待的时间，而 <strong>内联首屏关键 CSS（即 Critical CSS，可以称之为首屏关键 CSS）</strong> 能给用户一个更好的心理预期。</p><p>如图：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-1.png" class="kg-image" alt="image-1" width="801" height="412" loading="lazy"></figure><p>我们知道内联 CSS 能够使浏览器开始页面渲染的时间提前，即在 HTML 下载完成之后就能渲染了。</p><p>既然是内联关键 CSS，也就说明我们只会将少部分的 CSS 代码直接写入 HTML 中。至于内联哪些 CSS 你可以使用 Critical。</p><h3 id="6-">6. 文字两端对齐</h3><p>需求中我们也经常遇到这样的需求，这里直接提供方案。</p><pre><code class="language-JavaScript">// html
&lt;div&gt;姓名&lt;/div&gt;
&lt;div&gt;手机号码&lt;/div&gt;
&lt;div&gt;账号&lt;/div&gt;
&lt;div&gt;密码&lt;/div&gt;

// css
div {
margin: 10px 0;
width: 100px;
border: 1px solid red;
text-align: justify;
text-align-last:justify;
}
div:after{
content: '';
display: inline-block;
width: 100%;
}</code></pre><p>效果如下：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-2.png" class="kg-image" alt="image-2" width="584" height="244" loading="lazy"></figure><h3 id="7-">7. 样式的顺序</h3><p><strong>CSS 代码：</strong></p><pre><code class="language-CSS">.red {
color: red;
}
.blue {
color: blue;
}
</code></pre><p><strong>HTML 代码：</strong></p><pre><code class="language-HTML">&lt;div class="red blue"&gt;这是什么颜色&lt;/div&gt;
&lt;div class="blue red"&gt;这是什么颜色&lt;/div&gt;
</code></pre><p>记得之前这是一道比较火的 CSS 考题，当时好像是有不少的人答错（30% 以上）</p><h3 id="8-css-">8. 浏览器会从右到左解析 CSS 选择器</h3><pre><code class="language-CSS">.content_box div p a {
// ...
}</code></pre><p>浏览器会对上面的例子做如下的步骤处理：</p><ol><li>首先找到页面所有的 <code>&lt;a&gt;</code> 元素</li><li>然后向上找到被 <code>&lt;p&gt;</code> 元素包裹的 <code>&lt;a&gt;</code> 元素</li><li>再向上查找到一直到 <code>.content_box</code> 的元素</li></ol><p>从上面的步骤我们可以看出，越靠右的选择器越具有唯一性，浏览器解析 CSS 属性的效率就越高。</p><p>所以一定换成使用具体的 <code>class</code> 编写 CSS 代码。</p><h3 id="9-">9. 每个单词的首字母大写</h3><p>其实我第一次看到这个功能的时候就是使用 JS 去实现这个功能：</p><pre><code class="language-JavaScript">function capitalizeFirst( str ) {
let result = '';
result = str.toLowerCase().replace(/( |^)[a-z]/g, (L) =&gt; L.toUpperCase());
return result
}</code></pre><p>直到有一天看到 CSS 也能做这个功能的时候，我才反应过来明明一句 CSS 就能解决的问题，我却使用了更复杂的方案。</p><p>CSS 方案如下：</p><pre><code class="language-CSS">.capitalizeFirst-css {
text-transform: capitalize;
}</code></pre><p>是不是特别简单。</p><h4 id="text-transform-">text-transform 简单介绍</h4><p>这是 CSS2 中的属性，参数有 capitalize | uppercase | lowercase | none</p><p>参数介绍：</p><ol><li>none：默认。定义带有小写字母和大写字母的标准的文本。</li><li>capitalize：文本中的每个单词以大写字母开头。</li><li>uppercase：定义仅有大写字母。</li><li>lowercase：定义无大写字母，仅有小写字母。</li></ol><p>从这个属性我们可以知道全部大写（小写）的需求这个属性也能轻易实现。</p><h3 id="10-">10. 单选高亮</h3><p>可能你看到“单选高亮”没反应过来，直接来张图片你就马上清楚了：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-3.png" class="kg-image" alt="image-3" width="300" height="303" loading="lazy"></figure><p>这个需求用 CSS 更方便处理。主要代码就是一段 CSS 代码：</p><pre><code class="language-CSS">// 省略部分代码，详细代码看仓库
.input:checked + .colors {
border-color: #e63838;
color: #e63838;
}

&lt;div class="single-check"&gt;
&lt;input class="input" type="radio" name="colors" value="1"&gt;
&lt;div class="colors"&gt;天空之境&lt;/div&gt;
&lt;/div&gt;</code></pre><p><strong>看效果：</strong></p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/640.gif" class="kg-image" alt="640" width="468" height="179" loading="lazy"></figure><h4 id="--1">两个选择器的区别</h4><p><code>~选择器</code>：查找某个元素后面的所有兄弟元素</p><p><code>+选择器</code>：查找某个元素后面紧邻的兄弟元素</p><h3 id="11-">11. 多列等高问题</h3><p>有三种 CSS 的处理方案：</p><ol><li>每列设置一个很大的 padding，再设置一个很大的负的 margin</li><li>使用 <code>display:table;</code></li><li>使用 flex</li></ol><p>第一种有明显的缺陷：</p><ol><li><code>border-bottom</code> 看不到了</li><li>设置的下方的两个圆角也不见了</li></ol><p>所以可以使用 <code>display:table;</code> 或者 <code>flex布局</code> 的方式来实现等高。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-8.png" class="kg-image" alt="image-8" width="433" height="300" loading="lazy"></figure><p>建议不要一味的抵触 table，有的场景还是可以使用的。</p><h2 id="11-js-">11 个有趣实用的 JS 特性</h2><p>在日常开发中总是和各种 <code>API</code> 打交道，我们名为前端工程师实为 <code>API</code> 调用工程师。这里分享 11 个实用又有趣的 JS 特性，使用得当可以提高你应用的友好性。</p><h3 id="1-orientationchange">1. 监听屏幕旋转变化接口: orientationchange</h3><p><strong>定义：</strong></p><p>这个 <code>API</code> 可以将你手机是否横屏的情况暴露给需要知道的人知道。</p><p><strong>使用：</strong></p><pre><code class="language-JavaScript">screenOrientation: function(){
let self = this;
let orientation = screen.orientation || screen.mozOrientation || screen.msOrientation;
window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function() {
self.angle = orientation.angle;
});
},
</code></pre><p>orientation.angle 值屏幕方向0竖屏90向左横屏-90/270向右横屏180倒屏</p><p>通过这个 <code>API</code> 我们在横屏和竖屏的时候可以添加一些动作或者是样式的改变。</p><p>如果只是样式的改变也可以通过媒体查询来监听：</p><pre><code class="language-JavaScript">/* 竖屏 */
@media screen and (orientation: portrait) {
// some css code
}
/* 横屏 */
@media screen and (orientation: landscape) {
// some css code
}</code></pre><h3 id="2-navigator-getbattery-">2. 电池状态：navigator.getBattery()</h3><p><strong>定义：</strong></p><p>这个 <code>API</code> 可以将你手机电池状态的情况暴露给需要知道的人知道。</p><p>这个 <code>api</code> 返回的是一个 <code>promise</code> 对象，会给出一个 <code>BatteryManager</code> 对象，对象中包含了以下信息：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-9.png" class="kg-image" alt="image-9" width="680" height="406" loading="lazy"></figure><p><strong>使用：</strong></p><pre><code class="language-JavaScript">getBatteryInfo: function(){
let self = this;
if(navigator.getBattery){
navigator.getBattery().then(function(battery) {
// 判断是否在充电
self.batteryInfo = battery.charging ? `在充电 : 剩余 ${battery.level * 100}%` : `没充电 : 剩余 ${battery.level * 100}%`;
// 电池充电状态改变事件
battery.addEventListener('chargingchange', function(){
self.batteryInfo = battery.charging ? `在充电 : 剩余 ${battery.level * 100}%` : `没充电 : 剩余 ${battery.level * 100}%`;
});
});
}else{
self.batteryInfo = '不支持电池状态接口';
}
},</code></pre><h3 id="3-window-navigator-vibrate-200-">3. 让你的手机震动: window.navigator.vibrate(200)</h3><p><strong>定义：</strong></p><p>这个 <code>API</code> 可以让你的手机按你的想法震动。</p><p><strong>使用：</strong><br>震动效果会在很多游戏使用。比如欢乐斗地主中，地主打完王炸后手机都会有震动的效果，以此来表达地主嘚瑟的心情也很是合理。</p><p>示例代码如下：</p><pre><code class="language-JavaScript">vibrateFun: function(){
let self = this;
if( navigator.vibrate ){
navigator.vibrate([500, 500, 500, 500, 500, 500, 500, 500, 500, 500]);
}else{
self.vibrateInfo = "您的设备不支持震动";
}
&lt;!--
// 清除震动
navigator.vibrate(0);
// 持续震动
setInterval(function() {
navigator.vibrate(200);
}, 500);
--&gt;
},</code></pre><h3 id="4-navigator-language">4. 当前语言：navigator.language</h3><p><strong>定义：</strong></p><p>这个 <code>API</code> 可以告诉你当前应该使用什么语言。</p><p>如果你需要和我一样做多语言适配，这个 API 或许可以给你提供一个不错的思路。</p><p><strong>使用：</strong></p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-10.png" class="kg-image" alt="image-10" width="386" height="180" loading="lazy"></figure><p>不同浏览器返回的值稍微有点差异。你可以通过以下封装好的方法来消除这种差异：</p><pre><code class="language-JavaScript">function getThisLang(){
const langList = ['cn','hk','tw','en','fr'];
const langListLen = langList.length;
const thisLang = (navigator.language || navigator.browserLanguage).toLowerCase();
for( let i = 0; i &lt; langListLen; i++ ){
let lang = langList[i];
if(thisLang.includes(lang)){
return lang
}else {
return 'en'
}
}
}</code></pre><p>不同的语言就对应不同的语言文案就好。</p><h3 id="5-navigator-online">5. 联网状态：navigator.onLine</h3><p><strong>定义：</strong></p><p>这个 <code>API</code> 可以告诉让你知道你的设备的网络状态是否连接着。</p><p><strong>使用：</strong></p><p>比如我上午登陆了掘金在看一篇文章，可是没看完就到了吃饭的点，这么热爱学习的我肯定是选择吃完午饭回来继续看。</p><p>30 分钟过后……</p><p>吃晚饭回到公司，打开电脑继续把那篇文章看完，看完了打算点了赞，发现给了这个提示：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-11.png" class="kg-image" alt="image-11" width="505" height="189" loading="lazy"></figure><p>这个提示让我有点懵（就是没网络了）。</p><p>这个时候我们就可以使用这个 API，这样就可以准确的告诉用户“您的网络无法连接，请检查”。这样用户是不是可以有更好的体验呢？</p><p>代码如下：</p><pre><code class="language-JavaScript">mounted(){
let self = this;
window.addEventListener('online',  self.updateOnlineStatus, true);
window.addEventListener('offline', self.updateOnlineStatus, true);
},
methods: {
updateOnlineStatus: function(){
var self = this;
self.onLineInfo = navigator.onLine ? "online" : "offline";
},
}</code></pre><p>注意：<code>navigator.onLine</code> 只会在机器未连接到局域网或路由器时返回 <code>false</code>，其他情况下均返回 <code>true</code>。也就是说，机器连接上路由器后，即使这个路由器没联通网络， <code>navigator.onLine</code> 仍然返回 <code>true</code>。</p><h3 id="6-contenteditable">6. 页面可编辑：contentEditable</h3><p><strong>定义：</strong></p><p>这个 <code>API</code> 可以使页面所有元素成为可编辑状态，使浏览器变成你的编辑器。</p><p><strong>使用：</strong></p><ol><li>你可以在地址栏输入 <code>data:text/html,&lt;html contenteditable&gt;</code>, 这样浏览器就变成了编辑器。</li></ol><figure class="kg-card kg-image-card"><img src="https://mmbiz.qpic.cn/mmbiz_gif/iccXN8sGPLT7avmAGuTj0HHgUzG5jia3oLoaO4v3FUbwle9Aa8WKC5nmgEes8iboFjTN6dtZAVicJp7qCIIUkh06nQ/640?wx_fmt=gif&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1" class="kg-image" alt="640?wx_fmt=gif&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1" width="640" height="385" loading="lazy"></figure><p><strong>使用场景：</strong></p><p>需求 —— 页面需要一个文本输入框。</p><ol><li>该文本输入框默认状态下有默认文本提示信息</li><li>文本框输入状态下其高度会随文本内容自动撑开</li></ol><p>像这样的需求我们就可以使用 <code>&lt;divcontentEditable='true'&gt;&lt;/div&gt;</code> 代替 <code>&lt;textarea&gt;</code> 标签。</p><p>不过 <code>contentEditable='true'</code> 是不会有 placeholder 的，那 placeholder 怎么办呢？</p><p>我一般会使用如下方案，输入内容后改变 class：</p><pre><code class="language-JavaScript">&lt;div class='haveInput' contentEditable='true' placeholder='请输入'&gt;&lt;/div&gt;
// css 样式
.haveInput:before {
content: attr(placeholder);
display: block;
color: #333;
}</code></pre><p><strong>好玩的事儿</strong></p><p>你可以在浏览器的 consloe 控制台输入 <code>document.body.contentEditable=true</code>，你会发现整个页面都是可编辑的。</p><p>可以编辑页面内容，去逗一逗你的朋友，也是一个挺好玩的事儿。（下图我就修改了一些数据）</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-12.png" class="kg-image" alt="image-12" width="1080" height="391" loading="lazy"></figure><h3 id="7-window-onblur-window-onfocus">7. 浏览器活跃窗口监听: window.onblur &amp; window.onfocus</h3><p><strong>定义：</strong></p><p>这两个 api 分别表示窗口失去焦点和窗口处于活跃状态。</p><p>浏览其他窗口、浏览器最小化、点击其他程序等， window.onblur 事件就会触发;<br>回到该窗口，window.onfocus 事件就会触发。</p><p><strong>使用：</strong></p><figure class="kg-card kg-image-card"><img src="https://mmbiz.qpic.cn/mmbiz_gif/iccXN8sGPLT7avmAGuTj0HHgUzG5jia3oLTQrbyMcFapIaPtxXP9B0ficF3gNABG9ibE7jM5Dz0XMdWP9hPRdR9G5g/640?wx_fmt=gif&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1" class="kg-image" alt="640?wx_fmt=gif&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1" width="325" height="170" loading="lazy"></figure><p>上面的截图是微信网页版的消息提示。</p><p>代码很简单：</p><pre><code class="language-JavaScript">mounted(){
let self = this;
window.addEventListener('blur',  self.doFlashTitle, true);
window.addEventListener('focus', function () {
clearInterval(self.timer);
document.title = '微信网页版';
}, true);
},
methods: {
doFlashTitle: function(){
var self = this;
self.timer = setInterval( () =&gt; {
if (!self.flashFlag) {
document.title = "微信网页版";
} else {
document.title = `微信（${self.infoNum}）`;
}
self.flashFlag = ! self.flashFlag
}, 500)
},
}</code></pre><h3 id="8-api-fullscreen-api-">8. 全屏 API（Fullscreen API）</h3><p><strong>定义：</strong></p><p>这个 <code>API</code> 可以使你所打开的页面全屏展示，没有其他页面外的内容展示在屏幕上。</p><p><strong>使用：</strong></p><p>Element.requestFullscreen() 方法用于发出异步请求使元素进入全屏模式。</p><p>调用此 API 并不能保证元素一定能够进入全屏模式。如果元素被允许进入全屏幕模式，document 对象会收到一个 fullscreenchange 事件，通知调用者当前元素已经进入全屏模式。如果全屏请求不被许可，则会收到一个 fullscreenerror 事件。</p><p>当进入/退出全屏模式时,会触发 fullscreenchange 事件。你可以在监听这个事件，做你想做的事。</p><pre><code class="language-JavaScript">fullScreenFun: function(){
let self = this;
var fullscreenEnabled = document.fullscreenEnabled       ||
document.mozFullScreenEnabled    ||
document.webkitFullscreenEnabled ||
document.msFullscreenEnabled;

if (fullscreenEnabled) {
let de = document.documentElement;
if(self.fullScreenInfo === '打开全屏'){
if( de.requestFullscreen ){
de.requestFullscreen();
}else if( de.mozRequestFullScreen ){
de.mozRequestFullScreen();
}else if( de.webkitRequestFullScreen ){
de.webkitRequestFullScreen();
}
self.fullScreenInfo = '退出全屏'
} else {
if( document.exitFullscreen ){
document.exitFullscreen();
}else if( document.mozCancelFullScreen ){
document.mozCancelFullScreen();
}else if( document.webkitCancelFullScreen ){
document.webkitCancelFullScreen();
}
self.fullScreenInfo = '打开全屏'
}
} else {
self.fullScreenInfo = '浏览器当前不能全屏';
}
}</code></pre><p>相关：</p><ol><li>document.fullscreenElement: 当前处于全屏状态的元素 element</li><li>document.fullscreenEnabled: 标记 fullscreen 当前是否可用</li><li>document.exitFullscreen(): 退出全屏</li></ol><h3 id="9-a-url">9. 利用 a 标签解析 URL</h3><p>有的时候我们需要从一个 URL 中提取域名，查询关键字，变量参数值等，一般我们会自己去解析 URL 来获取这些内容。可是你或许不知道还有更简单的方法。</p><p>即创建一个 a 标签将需要解析的 URL 赋值给 a 的 href 属性，然后我们就能很方便的拿到这些内容。代码如下：</p><pre><code class="language-JavaScript">function parseURL(url) {
var a =  document.createElement('a');
a.href = url;
return {
host: a.hostname,
port: a.port,
query: a.search,
params: (function(){
var ret = {},
seg = a.search.replace(/^\?/,'').split('&amp;'),
len = seg.length, i = 0, s;
for (;i&lt;len;i++) {
if (!seg[i]) { continue; }
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;
})(),
hash: a.hash.replace('#','')
};
}</code></pre><h3 id="10-getboundingclientrect-">10. getBoundingClientRect() 知多少</h3><p>这个 <code>API</code> 可以告诉你页面中某个元素<strong>相对浏览器视窗</strong>上下左右的距离。</p><p><strong>使用：</strong><br>tab 吸顶可以使用 <code>obj.getBoundingClientRect().top</code> 代替 <code>scrollTop-offsetTop</code>，代码如下：</p><pre><code class="language-JavaScript">// html
&lt;div class="pride_tab_fixed" ref="pride_tab_fixed"&gt;
&lt;div class="pride_tab" :class="titleFixed == true ? 'isFixed' :''"&gt;
// some code
&lt;/div&gt;
&lt;/div&gt;

// vue
export default {
data(){
return{
titleFixed: false
}
},
activated(){
this.titleFixed = false;
window.addEventListener('scroll', this.handleScroll);
},
methods: {
//滚动监听，头部固定
handleScroll: function () {
let offsetTop = this.$refs.pride_tab_fixed.getBoundingClientRect().top;
this.titleFixed = offsetTop &lt; 0;
// some code
}
}
}</code></pre><h4 id="offsettop-getboundingclientrect-">offsetTop 和 getBoundingClientRect() 区别</h4><p><strong>1. getBoundingClientRect():</strong></p><p>用于获得页面中某个元素的左，上，右和下分别相对浏览器视窗的位置。不包含文档卷起来的部分。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-13.png" class="kg-image" alt="image-13" width="783" height="500" loading="lazy"></figure><p>该函数返回一个 <code>object</code> 对象，有8个属性：<code>top,right,buttom,left,width,height,x,y</code></p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2019/09/image-14.png" class="kg-image" alt="image-14" width="298" height="241" loading="lazy"></figure><p><strong>2. offsetTop:</strong></p><p>用于获得当前元素到定位父级（ element.offsetParent ）顶部的距离（偏移值）。</p><p>定位父级 <code>offsetParent</code> 的定义是：与当前元素最近的 position != static 的父级元素。</p><p><code>offsetTop</code> 和 <code>offsetParent</code> 方法相结合可以获得该元素到 <code>body</code> 上边距的距离。代码如下：</p><pre><code class="language-JavaScript">getOffset: function(obj,direction){
let offsetL = 0;
let offsetT = 0;
while( obj!== window.document.body &amp;&amp; obj !== null ){
offsetL += obj.offsetLeft;
offsetT += obj.offsetTop;
obj = obj.offsetParent;
}
if(direction === 'left'){
return offsetL;
}else {
return offsetT;
}
}</code></pre><h3 id="11-intersectionobserver-">11. IntersectionObserver 是什么？</h3><p>IntersectionObserver 可以用来监听元素是否进入了设备的可视区域之内，而不需要频繁的计算来做这个判断。</p><p>所以我们可以用这个特性来处理曝光埋点，而不是用 <code>getBoundingClientRect().top</code> 这种更加损耗性能的方式来处理。</p><p>当然你也可以用这个 API 来优化滚动吸顶,代码如下：</p><pre><code class="language-JavaScript">IntersectionObserverFun: function() {
let self = this;
let ele = self.$refs.pride_tab_fixed;
if( !!IntersectionObserver ){
let observer = new IntersectionObserver(function(){
let offsetTop = ele.getBoundingClientRect().top;
self.titleFixed = offsetTop &lt; 0;
}, {
threshold: [1]
});
observer.observe(document.getElementsByClassName('title_box')[0]);
} else {
window.addEventListener('scroll', _.throttle(function(){
let offsetTop = ele.getBoundingClientRect().top;
self.titleFixed = offsetTop &lt; 0;
}, 50));
}
},</code></pre> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
