前端小笔记

HTML

  1. HTML5新增加的内容或者API

    • API层

      • canvas: 用来写游戏还是很不错的,推荐开源游戏框架:pixi.js
      • 离线: 想起 Cache Manifest , 和 Cache APIs 。再加上 Service Worker 的特性,用户体验能提升不少。
      • 拖放: Drag & Drop , 对用户体验也有很大的提升。推荐开源库:dragula
      • 历史: 简而言之就是可以使用history对象控制地址了,一般会被单页应用用作路由控制,如果不支持,然后降级为hash。
      • 网络存储: sessionStorage & localStorage,这个应该不陌生,保存一些稍大的数据,或者不适合放在Cookie的,就用网络存储。 类似的还有 IndexedDB 和 WebSQL。 推荐开源库:localForage。
    • 元素与属性

      • section 文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。写文章的时候经常会用到
      • <video> 和 <audio>: 视频和音频。相关开源库:video.js。
      • <footer> 和 <header>: 之前<div class='footer OR header'></div>的写法换成标签<footer> 和 <header>就行了,为了语义化,推荐。
      • <mark> 标记高亮一个词。
      • <datalist> 提醒用户可以输入哪些,查看 w3school 的 demo。
      • <nav>表示导航等等,还要更多的标签,目的是为了写出更好语义化的HTML。
  2. input与textarea的区别

    • input
      • 可以指定 type 为 url, email, 可以方便地检测用户输入。还是指定为 file, submit, button, checkbox, radio, datetime, color等,改变input的样式和行为。
      • 可以通过 value 属性指定初始值
      • 宽高只能通过 CSS 指定
    • textarea
      • 可以输入多行文字
      • 输入值初始化需要用标签对包裹,并可以夹杂 HTML 代码,而不会被浏览器解析
          <textarea><h1>h1</h1></textarea>
      
      • 宽高能用 CSS 或 rows, cols 指定
    • 相同点
      • 都可以使用 maxlength, minlength等限制输入
  3. 用一个div模拟textarea的实现

    • 加个 contenteditable 属性就行
    • 在项目中如果需要用到富文本,在 Github 中搜索 rich editor 就行了,或者搜索 WYSIWYG (what you see is what you get), 百度的 ueditor 也是不错的
  4. 忽略页面中的电话号码

    <meta name="format-detection" content="telephone=no" />
    
  5. 左右布局:左边定宽、右边自适应

    • absolute + padding
      <style>
          .example-1 {
            position: relative;
            height: 100px;
            width: 60%;
            padding-left: 100px;
          }
          .example-1 .left {
            position: absolute;
            width: 100px;
            left: 0;
            height: 100%;
            background: #0f0;
          }
          .example-1 .right {
            background: #f00;
            width: 100%;
            height: 100%;
          }
      </style>
      <div class='example-1 auto-width'>
            <div class='left'>left</div>
            <div class='right'>right</div>
      </div>
      
    • flex布局未来趋势
    • table (内容过多时 会出问题)
      <style>
          .example-3 {
            display: table;
            height: 100px;
            width: 60%;
          }
          .example-3 .left {
            width: 100px;
            height: 100%;
            background: #0f0;
            display: table-cell;
          }
          .example-3 .right {
            background: #f00;
            height: 100%;
            display: table-cell;
          }
      </style>
      <div class='example-3 auto-width'>
        <div class='left'>left</div>
        <div class='right'>right</div>
      </div>
      
    • float解决方案
      <style>
          .example-4 {
            height: 100px;
            width: 60%;
          }
          .example-4 .left {
            float: left;
            width: 100px;
            height: 100%;
            background: #0f0;
          }
          .example-4 .right {
            background: #f00;
            overflow: hidden;
            height: 100%;
          }
      </style>
      <div class='example-4 auto-width'>
        <div class='left'>left</div>
        <div class='right'>right</div>
      </div>
      
  6. BFC、IFC

    • BFC: ‘Block Formatting Context’, BFC 表现原则: 内部子元素再怎么翻江倒海,翻云覆雨都不会影响外部的元素,自成一方天地。
    • IFC: Inline Formatting Contexts, 直译为”内联格式化上下文”,个人理解为行内盒子模型。
  7. 图片懒加载
    核心代码时检测当前元素是否在当前视图中:

    function elementInViewport(el) {
        var rect = el.getBoundingClientRect()
    
        // For invisible element. 对于不可见元素
        if (rect.top + rect.bottom + rect.left + rect.right + rect.height + rect.width === 0) {
          return false;
        }
    
        return (
           rect.top   >= 0
            // Pre load.
            && rect.top   <= ((window.innerHeight || document.documentElement.clientHeight) + 100)
            && rect.left  >= 0
            // Hide carousel except the first image. Do not add equal sign.
            && rect.left  < (window.innerWidth || document.documentElement.clientWidth)
        )
    }
    
  8. 实现页面加载进度条

    • AJAX
    • Elements
    • Document
    • Event Lag
  9. 事件委托
    利用事件冒泡e.target来确定事件和元素。在jQuery中有$.delegate方法去代理事件。使用委托代理的原因:

    • 需要绑定事件的元素很多,且处理逻辑类似。
    • 元素是动态创建,或频繁增加、删除,导致元素绑定事件过于复杂的。
    // 参考 https://github.com/zenorocha/delegate/blob/master/src/delegate.js
    const delegate = (element, selector, type, callback) => {
      element.addEventListener(type, (e) => {
        let target = e.path.find(ele => ele.matches(selector))
        if (target) {
          callback.call(element, e);
        }
      });
    };
    
  10. 实现 extend 函数
    浅拷贝使用 Object.assign 就够了,大多数情况下,使用该方法。
    直接 Clone 一个 Nested Object 的简便方法:

    var origin = {"a": "a"}
    var copy = JSON.parse(JSON.stringify(origin));
    
  11. 跨域的问题以及解决方式

    • 解决方式:

      • JSONP(JSON with Padding): 利用加载 JS 文件不需要遵循同源策略的原理。
      • CORS(Cross-Origin Resource Sharing): 在服务器端返回允许跨域访问的头。
      • WebSockt:利用 WebSocket 不需要遵循同源策略的原理。
    • JSONP
      JSONP 原理是加载一个 script,并执行一段回调 JS ,因为加载 JS 不需要遵循同源策略。但由此也带来了JSONP的一些问题:

      • 无法发送特定的头部
      • 只能是 GET 请求
      • 无法发送 body
  12. 拖拽功能

    <ul id='drag'>
      <li draggable="true">1</li>
      <li draggable="true">2</li>
      <li draggable="true">3</li>
      <li draggable="true">4</li>
      <li draggable="true">5</li>
    </ul>
    <script>
      var ele;
      document.querySelector('#drag').addEventListener('dragstart', function (e) {
        ele = e.target;
        ele.classList.add('draging');
      })
      document.querySelector('#drag').addEventListener('dragover', function (e) {
        e.preventDefault();
    
        if (e.target.nodeName === 'LI') {
          e.target.parentNode.insertBefore(ele, e.target);
        }
      })
      document.querySelector('#drag').addEventListener('drop', function (e) {
        ele.classList.remove('draging');
      })
    </script>
    
  13. 手写parseInt的实现

    • const parseInt = str => str - 0;
    • const parseInt = str => str / 1;
    • const parseInt = str => str * 1;
    • const parseInt = str => +str;
    • 复杂写法
    const parseInt = str => {
      let n = 0;
      let i = 1;
      str.split('').reverse().map(s => {
        n += i * (s.charCodeAt(0) - 48);
        i *= 10;
      });
      return n;
    }
    
  14. 分页器组件
    为了减少服务端查询次数,点击“下一页”怎样能确保还有数据可以加载(请求数据不会为空)?

    • 服务器需要返回总数,当前偏移量,根据总数和偏移量判断是否是最后一页。
    • 参考微信的接口,给一个下一页的起始项的id,如果当前页最后一个id和下一页起始id相同,就是最后一页。
  15. require.js的实现原理
    与webpack相比,两者打包的异同及优缺点

    • 同:
      都以模块化方式组织代码
    • 异:
      requirejs 只能加载JS文件
      webpack 可以打包JS,CSS,甚至是图片
  16. 项目中使用过哪些优化方法

    • 页面静态化,(如:Jada, Pug在静态编译后部署)
    • CDN加速, 多地缓存
    • 前端渲染 (Data + View) / 后端渲染( SSR, SEO 等), 视具体情况选择,如:
      • 前端渲染,适合大流量的场景
      • 后端渲染,适合SEO优化,用户体验提升等场景
    • 缩减域名,以减少DNS解析时间,(可采用<link rel="dns-prefetch" href="//xxx.com">进行优化)
      • 如果遇到域名解析的问题,可尝试HTTPDNS方案
    • Combo服务器合并CSS,JS请求,减少第一屏网络请求。(如果采用HTTP2.0方案,资源合并可省略)
    • 异步加载非核心业务和逻辑资源
    • 资源和请求缓存,可参考缓存的答案
      • Cache-Control/Expires 前端缓存
      • Last-Modified/Etag 服务器端缓存,304
    • 如果是和Native混合开发的,还可以使用Native缓存
    • DNS就近解析应用服务器,需要和CDN配合使用
  17. 输入一个URL,Enter之后发生了什么

    • 浏览器解析URL, 如: https://www.google.com.hk/#newwindow=1&q=hello
      • 协议:http, https等
      • 域名:www.google.com.hk
      • 资源路径: /
      • 参数查询:q=hello, 关键词hello
    • DNS
      • 浏览器 DNS 缓存
      • HOSTS 查询
      • DNS 服务器查询
      • ARP 查询
    • TCP 握手, TLS 握手
    • HTTP(s), (或SPDY, 或HTTP2.0)
      • Header
      • Domain
      • Body
    • Gateway / Nginx,网关和负载均衡服务器
      • 查询本地缓存
      • 请求上游应用服务器
    • 浏览器解析HTML,并请求资源
      • CSS
      • JS
      • 图片
    • 生成 DOM-Tree,结合CSS进行渲染
  18. 页面的渲染过程

    • 解析整个HTML,得到DOM树和样式树
    • DOM树和样式树,经过渲染,得到一颗渲染树
    • 根据渲染树,开始布局,计算各个节点宽度,位置,高度等
    • 然后开始绘制整个页面并显示
    • 在渲染过程中如果使用了GPU,还可以进行GPU渲染
  19. 静态资源或者接口等如何做缓存优化

    • redis/memcache 做数据缓存
    • SQL 查询做缓存
    • 指定 Cache-Control/Expires 缓存时间
    • Last-Modified/Etag 缓存 ( 304 ) 方案
    • 网关服务器做缓存,需要更新时,再回源到应用服务器
    • CDN多机房,多网关缓存
  20. 页面DOM节点太多,会出现什么问题?如何优化?

    • 页面卡顿,帧率下降
    • 优化:
      • 采用Virtual Dom技术,可参考: virtual-dom
      • 多次操作DOM,改为批量一次操作DOM
      • 及时移走页面不用的DOM
      • 避免不必要的DIV嵌套

前端安全问题 CSRF和XSS

  1. CSRF Cross-site request forgery 跨站请求伪造

    • 简单描述:

      跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。[1] 跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任

    • 防御措施

      • 检查referer, X-Requested-With, Orign头
      • 使用POST代替GET
      • 添加校验Token至表单中
      • 添加验证码或其他人机验证手段,如 Google 的 recaptcha
      • Token放到自定义的HTTP Header, Cookie-to-Header Token
  2. XSS: Cross-site_scripting

    • 简单描述:

    跨站脚本(英语:Cross-site scripting,通常简称为:XSS)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。

    • 防御措施
      • 过滤特殊字符串 ( encoding / escaping )
      • 保护Cookie
      • 使用HttpOnly字段防止被JS获取,(因为攻击通常会采集敏感信息)
      • 使用HTTPs代替HTTP,(运营商经常会通过注入广告)
      • 禁用JS,(这个不太现实)
      • 推荐!设置CSP: Content_Security_Policy 介绍,Content-Security-Policy 文档。这个在Github有使用:
        Content-Security-Policy:default-src 'none'; base-uri 'self'; block-all-mixed-content; child-src render.githubusercontent.com; connect-src 'self' uploads.github.com status.github.com collector.githubapp.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com wss://live.github.com; font-src assets-cdn.github.com; form-action 'self' github.com gist.github.com; frame-ancestors 'none'; img-src 'self' data: assets-cdn.github.com identicons.github.com collector.githubapp.com github-cloud.s3.amazonaws.com *.githubusercontent.com; media-src 'none'; script-src assets-cdn.github.com; style-src 'unsafe-inline' assets-cdn.github.com
        
      • 设置 X-XSS-Protection 头
  3. HTTP 安全头

    • Strict-Transport-Security: Strict-Transport-Security: max-age=31536000 ; includeSubDomains
    • Public-Key-Pins: Public-Key-Pins: pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; report-uri="http://example.com/pkp-report"; max-age=10000; includeSubDomains
    • X-Frame-Options: X-Frame-Options: deny
    • X-XSS-Protection: X-XSS-Protection: 1; mode=block
    • X-Content-Type-Options: X-Content-Type-Options: nosniff
    • Content-Security-Policy: Content-Security-Policy: script-src 'self'
    • X-Permitted-Cross-Domain-Policies: X-Permitted-Cross-Domain-Policies: none
    • Referrer-Policy: Referrer-Policy: no-referrer

跨域

跨域请求的含义

  1. 浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如JavaScript)对不同域的服务进行跨站调用。

  2. 一般的,只要网站的 协议名protocol、 主机host、 端口号port 这三个中的任意一个不同,网站间的数据请求与传输便构成了跨域调用。

  3. 跨域请求并非是浏览器限制了发起跨站请求,而是请求可以正常发起,到达服务器端,但是服务器返回的结果会被浏览器拦截。

利用 JSONP 实现跨域调用

JSONP 是 JSON 的一种使用模式,可以解决主流浏览器的跨域数据访问问题。其原理是根据XmlHttpRequest 对象受到同源策略的影响,而<script>标签元素却不受同源策略影响,可以加载跨域服务器上的脚本,网页可以从其他来源动态产生JSON资料。用JSONP获取的不是 JSON 数据,而是可以直接运行的 JavaScript 语句。

  • 如果理解 JSONP 的原理的话就不难理解为什么只能使用 GET 请求方法了。
    由于是通过 script 标签进行请求,所以上述传输过程根本上是以下的形式:
    <script src = 'http://localhost:3001/ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032'></script>

  • JSONP总结:

    1. 只能使用 GET 方法发起请求,这是由于 script 标签自身的限制决定的。
    2. 不能很好的发现错误,并进行处理。
    3. 与 Ajax 对比,由于不是通过 XmlHttpRequest 进行传输,所以不能注册 success、 error 等事件监听函数。
    <script>
         // function success_jsonpCallback(data) {
        //   console.log("in success_jsonpCallback ")
        //   console.log(data)
        // }
        $.ajax({
          type:'get',
          dataType:'jsonp',
          url:'http://localhost:3000/users/list',
          jsonp:"callback123",
          jsonpCallback:"success_jsonpCallback",
          success:function(res) {
            console.log(res)
          },
          error:function(err,status) {
            console.log(err)
            console.log(status)
          }
        })
      </script>
      <!--
        后台拿到的 req.query 对象
        { callback123: 'success_jsonpCallback', _: '1498535014927' }
        发送的ajax请求是:
            /users/list?callback123=success_jsonpCallback&_=1498535569911 
      -->
    

    服务器端 (需要返回函数的调用形式)

    router.get('/list', function(req, res, next) {
      console.log(req.query)
      var users = [
        {id:1, name:"F"},
        {id:2, name:"Z"},
        {id:3, name:"X"},
        {id:4, name:"M"},
        {id:5, name:"N"},
        {id:6, name:"A"},
        {id:7, name:"B"},
        {id:8, name:"D"},
        {id:9, name:"C"},
        {id:10, name:"L"},
      ];
      var data = req.query.callback123+"("+JSON.stringify(users)+")";
      res.send(data);
    });
    

使用 CORS 实现跨域调用

1 什么是 CORS?

Cross-Origin Resource Sharing(CORS)
跨域资源共享是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以让网页设计师用一般的 XMLHttpRequest,这种方式的错误处理比 JSONP 要来的好。另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。现代的浏览器都支持 CORS。

  1. 服务器端控制

    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    
  2. CORS 与 JSONP 的对比

    1. CORS 除了 GET 方法外,也支持其它的 HTTP 请求方法如 POST、 PUT 等。
    2. CORS 可以使用 XmlHttpRequest 进行传输,所以它的错误处理方式比 JSONP 好。
    3. JSONP 可以在不支持 CORS 的老旧浏览器上运作。

一些其它的跨域调用方式

  1. window.name

window对象有个name属性,该属性有个特征:即在一个窗口 (window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对 window.name 都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。

  1. window.postMessage()

这个方法是 HTML5 的一个新特性,可以用来向其他所有的 window 对象发送消息。需要注意的是我们必须要保证所有的脚本执行完才发送 MessageEvent,如果在函数执行的过程中调用了他,就会让后面的函数超时无法执行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,699评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,124评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,127评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,342评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,356评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,057评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,654评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,572评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,095评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,205评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,343评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,015评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,704评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,196评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,320评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,690评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,348评论 2 358

推荐阅读更多精彩内容