前端ARTS打卡计划(三)

2020/08/24 ARTS 本文共9924字,阅读全文约需38分钟 本文总阅读量

  前端 ARTS 打卡计划(三)。

ARTS 打卡计划

第二十一周(2020.08.24-2020.08.30)

  • Algorithm:

  • Review:

  • Tip:

    • IE 不支持箭头函数;脚本里 console.log 可能获取不到 console
    • window.location.origin 不兼容 IE,使用以下方法或者用其他属性(host、href 等)兼容替代
    if (!window.location.origin) {
      window.location.origin =
        window.location.protocol +
        '//' +
        window.location.hostname +
        (window.location.port ? ':' + window.location.port : '');
    }
    
  • Share:

第二十二周(2020.08.31-2020.09.06)

  • Algorithm:

  • Review:

  • Tip:

    • css 隐藏滚动条:自定义滚动条的伪对象选择器::-webkit-scrollbar
    <!-- chrome 和Safari -- > .element::-webkit-scrollbar {
      width: 0 !important;
    }
    <!-- IE 10 + -- > .element {
      -ms-overflow-style: none;
    }
    <!-- Firefox -- > .element {
      overflow: -moz-scrollbars-none;
    }
    

    参考:3 种方法实现 CSS 隐藏滚动条并可以滚动内容

    • js 手动触发窗口 resize 事件

      function doResize() {
        setTimeout(function () {
          //手动触发窗口resize事件
          if (document.createEvent) {
            var event = document.createEvent('HTMLEvents');
            event.initEvent('resize', true, true);
            window.dispatchEvent(event);
          } else if (document.createEventObject) {
            window.fireEvent('onresize');
          }
        }, 100);
      }
      
      // MDN
      // 创建事件
      var event = document.createEvent('Event');
      
      // 定义事件名为'build'.
      event.initEvent('build', true, true);
      
      // 监听事件
      elem.addEventListener(
        'build',
        function (e) {
          // e.target matches elem
        },
        false
      );
      
      // 触发对象可以是任何元素或其他事件目标
      elem.dispatchEvent(event);
      

      参考:MDN Document.createEvent()

    • nginx 部署丢失 JS、CSS、图片解决办法(Uncaught SyntaxError: Unexpected token '<'

      # 本示例为项目部署KUN的nginx.conf文件配置
      server {
              listen       3000;
              listen       [::]:3000;
              server_name  0.0.0.0;
              charset      utf-8;
      
              location / {
                  root   /usr/share/nginx/html;
                  try_files $uri /index.html;
                  index  index.html index.htm;
              }
              # 不配置可能找不到静态资源:Uncaught SyntaxError: Unexpected token '<'
              location ~ .*\.(js|map|css|jpegcss|swf|ico|txt|html|less|jar|tpl|tgz|woff|tff)$ {
                      root /usr/share/nginx/html;
                      proxy_redirect off;
                      expires 30d;
              }
      }
      
    • Safari 浏览器打开控制台:首先在浏览器偏好设置高级中勾选“开发”菜单的展示,然后option + command + c或者在开发菜单中选择“显示 JavaScript 控制台”。

  • Share:

第二十三周(2020.09.07-2020.09.13)

  • Algorithm:

  • Review:

  • Tip:

    • net::ERR_CERT_AUTHORITY_INVALID:https 网站,访问 htpps 的图片,302 重定向到 http 的图片,浏览器又把 http 协议自动转为 https 协议去请求图片,对应 https 路径无对应资源;
    • 验证邮箱格式正确性和合法性(如:非特定邮箱)
    let checkEmailResult = {};
    // handleEmailChange方法
    handleEmailChange = ({ target: { value } }) => {
      let FEdCheck = /^[\w-]+(\.[\w-]+)*(@[\w-]+(\.[\w-]+)+$)/.exec(value);
      // 前端验证合法性
      if (!FEdCheck) {
        checkEmailResult = {
          validateStatus: 'error', //  'success', 'warning', 'error', 'validating'
          help: '无效的邮箱',
        };
      } else if (FEdCheck[2] === '@ucloud.cn') {
        // 非特定邮箱
        checkEmailResult = {
          validateStatus: 'error',
          help: '邮箱不能为UCloud员工邮箱',
        };
      } else {
        // 接口验证可用性后
        checkEmailResult = {
          validateStatus: 'success',
          help: '',
        };
      }
    };
    
    // 组件
    <FormItem {...formItemLayout} label='邮箱' {...checkEmailResult}>
      {getFieldDecorator('Email', {
        rules: [{ required: true, message: '必填项!' }],
        initialValue: '',
      })(<Input onBlur={this.handleEmailChange} />)}
    </FormItem>;
    
  • Share:

第二十四周(2020.09.14-2020.09.20)

  • Algorithm:

  • Review:

  • Tip:

    • Cmder 设置默认打开目录

      • win + alt + p 打开设置
      • 选择 Startup-Task,修改{cmd::Cmder}项。把cmd /k "%ConEmuDir%\..\init.bat" -new_console:d:%USERPROFILE%修改为cmd /k "%ConEmuDir%\..\init.bat" -new_console:d:D:\XXX目录
      • 重启 cmder
      • 同样也可以修改打开 cmder 的时候进入的操作模式(cmder、PowerShell、bash 等等)
    • 使用mobx-react@inject("store") @observer包裹组件后,通过 ref 取被包裹组件上的方法/属性:this.refs.XXXXXXXXRef.wrappedInstance.open(record)(在被包裹组件内部调用 store 中的方法或者直接使用解构语法,貌似会导致 store 中方法的 this 丢失),常规:this.refs.XXXXXXXXRef.open(record)

    • 使用 create-react-app 创建项目后,kun 平台 build 部署报错:打开项目 package.json ,将 less 版本降到 3.0 以下,比如安装 2.7.3 版本(yarn add less@^2.7.3),也可参考issues

      Creating an optimized production build...
      Failed to compile.
    
      ./node_modules/antd/lib/message/style/index.less
      Module build failed:
      // https://github.com/ant-design/ant-motion/issues/44
      .bezierEasingMixin();
      ^
      Inline JavaScript is not enabled. Is it set in your options?
        in /app/node_modules/antd/lib/style/color/bezierEasing.less (line 110, column 0)
    

    antd 按需加载,配置 babel-plugin-import 插件,编译后报错.bezierEasingMixin()

    • 可以通过类似document.getElementsByTagName('input')[0].disabled = falseinput等标签的disabled失效;

    • hosts 文件位置:

      • Window 系统:C:\Windows\System32\drivers\etc,可Window + R打开“运行”,黏贴以上地址回车打开或者vim C:\Windows\System32\drivers\etc\hosts
      • Mac:vim /etc/hosts或者参考这里
    • 提交按钮固定在页面左下角

    DOM:

      <div className={styles.submitStyle}>
        <Button
          type="primary"
          loading={submitLoading}
          style=
          onClick={submitOA}
        >
          提交审批
        </Button>
      </div>
    

    样式:

    .submitStyle {
      position: fixed;
      bottom: 18px;
      right: 0;
      z-index: 1;
      width: 200px;
      background-color: rgba(0, 0, 0, 0.08);
      height: 60px;
      display: flex;
      align-items: center;
      justify-content: center;
      // & > div > div > span {
      //    display: flex;
      //    justify-content: space-around;
      // }
    }
    
    .submitStyle::before {
      content: '';
      width: 0;
      height: 0;
      border-width: 60px 0px 60px 40px;
      border-style: solid;
      border-color: transparent transparent rgba(0, 0, 0, 0.08);
      margin-bottom: 60px;
      margin-left: -40px;
    }
    

    效果图:
    提交按钮固定在页面左下角

  • Share:

第二十五周(2020.09.21-2020.09.27)

第二十六周(2020.09.28-2020.10.04)

  • Algorithm:

  • Review:

  • Tip:

    • escape、encodeURI 和 encodeURIComponent 的区别
      • escape 是对字符串(string)进行编码(而另外两种是对 URL),作用是让它们在所有电脑上可读。编码之后的效果是%XX或者%uXXXX这种形式。其中 ASCII 字母、数字、@*/+ ,这几个字符不会被编码,其余的都会。最关键的是,当你需要对 URL 编码时,请忘记这个方法,这个方法是针对字符串使用的,不适用于 URL;
      • encodeURI 和 encodeURIComponent 都是编码 URL,唯一区别就是编码的字符范围;
      • encodeURI 方法不会对下列字符编码:ASCII 字母、数字、~!@#$&*()=:/,;?+';encodeURIComponent 方法不会对下列字符编码:ASCII 字母、数字、~!*()'
      • 也就是 encodeURIComponent 编码的范围更广,会将http://XXX中的//也编码,会导致 URL 不可用。(其实 java 中的 URLEncoder.encode(str,char)也类似于这个方法,会导致 URL 不可用)。
      • 使用场景:
        • 如果只是编码字符串,不和 URL 有半毛钱关系,那么用 escape,而且这个方法一般不会用到。
        • 如果你需要编码整个 URL,然后需要使用这个 URL,那么用 encodeURI。
        • 当你需要编码 URL 中的参数的时候,那么 encodeURIComponent 是最好方法。
      • 如果不生效可以用两次编码:关于两次编码的原因
  • Share:

第二十七周(2020.10.05-2020.10.11)

第二十八周(2020.10.12-2020.10.18)

  • Algorithm:

    • 1544. 整理字符串
    • 925. 长按键入
      // 正则匹配解法
      var isLongPressedName = function (name, typed) {
        let nameReg = '^';
        let count = 1;
        for (let i = 0, len = name.length; i < len; i++) {
          if (name[i] === name[i + 1]) {
            count++;
          } else {
            nameReg += name[i] + `{${count},}`;
            count = 1;
          }
        }
        // 下面的解法会超时(输入`aaaaaaaaaaaaaaaaaaaaaaaa`)
        // name.split('').forEach(item => {
        //     nameReg += item + '{1,}'
        // })
        return new RegExp(nameReg + '$').test(typed);
      };
      
    • 面试题 01.03. URL 化
  • Review:

  • Tip:

    • 全面了解移动端 DNS 域名劫持等杂症:原理、根源、HttpDNS 解决方案等:HTTPDNS 利用 HTTP 协议与 DNS 服务器交互,代替了传统的基于 UDP 协议的 DNS 交互,绕开了运营商的 Local DNS,有效防止了域名劫持,提高域名解析效率。另外,由于 DNS 服务器端获取的是真实客户端 IP 而非 Local DNS 的 IP,能够精确定位客户端地理位置、运营商信息,从而有效改进调度精确性。

      • 客户端直接访问 HttpDNS 接口,获取业务在域名配置管理系统上配置的访问延迟最优的 IP。(基于容灾考虑,还是保留次选使用运营商 LocalDNS 解析域名的方式)
      • 客户端获取到 IP 后就直接向此 IP 发送业务协议请求。以 Http 请求为例,通过在 header 中指定 host 字段,向 HttpDNS 返回的 IP 发送标准的 Http 请求即可。
  • Share:

第二十九周(2020.10.19-2020.10.25)

第三十周(2020.10.26-2020.11.01)

  • Algorithm:

  • Review:

  • Tip:

    • EJS online | GitHub ejs

      3 版本 Console Importer CDN 地址安装:$i('https://npmcdn.com/ejs@3.1.6/ejs.min.js')

    • EJS 标签含义

      • <% ‘脚本’ 标签,用于流程控制,无输出。
      • <%_ 删除其前面的空格符
      • <%= 输出数据到模板(输出是转义 HTML 标签)
      • <%- 输出非转义的数据到模板
      • <%# 注释标签,不执行、不输出内容
      • <%% 输出字符串 ‘<%’
      • %> 一般结束标签
      • -%> 删除紧随其后的换行符
      • _%> 将结束标签后面的空格符删除
    • ReferenceError: primordials is not defined:可能是 node 版本过高的原因,可以用 nvm 管理 node 版本。nvm 全名 node.js version management,是一个 nodejs 的版本管理工具。通过它可以安装和切换不同版本的 nodejs。

      • 命令提示
        • nvm arch :显示 node 是运行在 32 位还是 64 位。
        • nvm install [arch] :安装 node, version 是特定版本也可以是最新稳定版本 latest。可选参数 arch 指定安装 32 位还是 64 位版本,默认是系统位数。可以添加--insecure 绕过远程服务器的 SSL。
        • nvm list [available] :显示已安装的列表。可选参数 available,显示可安装的所有版本。list 可简化为 ls。
        • nvm on :开启 node.js 版本管理。
        • nvm off :关闭 node.js 版本管理。
        • nvm proxy [url] :设置下载代理。不加可选参数 url,显示当前代理。将 url 设置为 none 则移除代理。
        • nvm node_mirror [url] :设置 node 镜像。默认是https://nodejs.org/dist/。如果不写url,则使用默认url。设置后可至安装目录settings.txt文件查看,也可直接在该文件操作。
        • nvm npm_mirror [url] :设置 npm 镜像。https://github.com/npm/cli/archive/。如果不写url,则使用默认url。设置后可至安装目录settings.txt文件查看,也可直接在该文件操作。
        • nvm uninstall :卸载指定版本 node。
        • nvm use [version] [arch] :使用制定版本 node。可指定 32/64 位。
        • nvm root [path] :设置存储不同版本 node 的目录。如果未设置,默认使用当前目录。
        • nvm version :显示 nvm 版本。version 可简化为 v。
        • nvm alias default v14.17.0:nvm 设置 nodejs 默认版本,避免每次重启都需要重新设置。
    • Object.prototype.toString.call()判断数据类型:

      Object.prototype.toString.call(123);
      //"[object Number]"
      Object.prototype.toString.call('str');
      //"[object String]"
      Object.prototype.toString.call(true);
      //"[object Boolean]"
      Object.prototype.toString.call({});
      //"[object Object]"
      Object.prototype.toString.call([]);
      //"[object Array]"
      getType = (obj) => {
        // 更简洁的写法:Object.prototype.toString.call(obj).slice(8, -1)
        return Object.prototype.toString
          .call(obj)
          .replace(/\[|\]/g, '')
          .substr(7);
      };
      getType(12n); // BigInt
      getType(Symbol()); // Symbol
      getType(() => {}); // Function
      getType(); // Undefined
      getType(null); // Null
      getType(NaN); // Number
      

      其他方法:typeofinstanceofconstructor【constructor 属性是可以被修改的,会导致检测出的结果不正确。除了undefinednull,其他类型的变量均能使用 constructor 判断出类型】。

      let bool = true;
      bool.constructor == Boolean; //true
      let num1 = 1;
      num1.constructor == Number; //true
      let num2 = new Number();
      num2.constructor == Number; //true
      // constructor属性是可以被修改的
      num2.constructor = Object;
      num2.constructor == Number; //false
      let str = 'hello world';
      str.constructor == String; //true
      
    • 跨平台应用开发:

      • Native
      • QT(WPS、汽车行业)
      • Flutter
      • NW.js(微信开发者工具)
      • Electron(VS Code、Atom) Electron
      • 其他:Carlo、WPF、CEF(Chromium Embedded Framework)、PWA cross platform
  • Share:

Search

    欢迎与我交流

    江南逰子

    Table of Contents