into-piece / Step-By-Step

每天一题向前端架构师前进
4 stars 1 forks source link

20200427 #21

Open into-piece opened 4 years ago

into-piece commented 4 years ago

Observer api

IntersectionObserver

提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。祖先元素与视窗(viewport)被称为根(root)。

// demo 达成lazyload
var intersectionObserver = new IntersectionObserver(function(entries) {
  // If intersectionRatio is 0, the target is out of view
  // and we do not need to do anything.
  if (entries[0].intersectionRatio <= 0) return;

  loadItems(10);
  console.log('Loaded new items');
});
// start observing
intersectionObserver.observe(document.querySelector('.scrollerFooter'));

工具=》https://codepen.io/michellebarker/full/xxwLpRG(辅助

Proxy和Reflect

组合达成校验器

function proxyValidator(target: any, validator: any) {
  return new Proxy(target, {
    set: function (target, propKey, value, receiver) {
      if (!!validator[propKey](value)) {
        console.log('=====right');
        return Reflect.set(target, propKey, value, receiver);
      } else {
        throw Error(`值校验错误${String(propKey)}:${value}`);
      }
    },
  });
}

// 用法
const personObj = {
  name: '123',
};

const validator = {
  name: (v: any) => {
    return typeof v === 'string';
  },
};
const formdata = proxyValidator(personObj, validator);
formdata.name = '123';

reflect

reflect 把object一些明显属于语言内部的方法的方法移植到reflect(比如Object.defineProperty)

// 老写法
'assign' in Object // true
// 新写法
Reflect.has(Object, 'assign') // true

CustomEvent 自定义事件

// 添加一个适当的事件监听器
dom1.addEventListener("boom", function(e) { something(e.detail.num) })

// 创建并分发事件
var event = new CustomEvent("boom", {"detail":{"num":10}})
dom1.dispatchEvent(event)

我们来看看CustomEvent的参数介绍:

type 事件的类型名称,如上面代码中的'boom' CustomEventInit 提供了事件的配置信息,具体有以下几个属性

bubbles 一个布尔值,表明该事件是否会冒泡 cancelable 一个布尔值,表明该事件是否可以被取消 detail 当事件初始化时传递的数据

我们可以通过dispatchEvent来触发自定义事件.其实他的用途有很多,比如创建观察者模式, 实现数据双向绑定, 亦或者在游戏开发中实现打怪掉血,

Typescript + Throttle + Hook

关于typescript的定时器setInterval()坑

// 定时器设置类型

function throttle (func: () => void, delay: number) {
  let timer: NodeJS.Timer | null = null
  return (...args : any[]) => {
    if(timer){
      timer = setTimeout(()=>{
        func.apply(this, args)
        clearTimeout(Number(timer))
        timer = null
      }, delay)
    }
  }
}

let timer: NodeJS.Timer | null = null // 设置
clearTimeout(Number(timer)) // 清除

react-use useThrottle实现

EventSource (Server-sent events的h5接口

EventSource 是服务器推送的一个网络事件接口。一个EventSource实例会对HTTP服务开启一个持久化的连接,以text/event-stream 格式发送事件, 会一直保持开启直到被要求关闭。

一旦连接开启,来自服务端传入的消息会以事件的形式分发至你代码中。如果接收消息中有一个事件字段,触发的事件与事件字段的值相同。如果没有事件字段存在,则将触发通用事件。

与 WebSockets,不同的是,服务端推送是单向的。数据信息被单向从服务端到客户端分发. 当不需要以消息形式将数据从客户端发送到服务器时,这使它们成为绝佳的选择。例如,对于处理社交媒体状态更新,新闻提要或将数据传递到客户端存储机制(如IndexedDB或Web存储)之类的,EventSource无疑是一个有效方案。

front-end

var evtSource = new EventSource('sse.php');
var eventList = document.querySelector('ul');

evtSource.onmessage = function(e) {
  var newElement = document.createElement("li");

  newElement.textContent = "message: " + e.data;
  eventList.appendChild(newElement);
}

node

  const sse = new EventSource('/api/v1/sse');

  /* This will listen only for events 
   * similar to the following:
   * 
   * event: notice
   * data: useful data
   * id: someid
   *
   */
  sse.addEventListener("notice", function(e) { 
    console.log(e.data)
  })

  /* Similarly, this will listen for events 
   * with the field `event: update`
   */
  sse.addEventListener("update", function(e) {
    console.log(e.data)
  })

  /* The event "message" is a special case, as it
   * will capture events without an event field
   * as well as events that have the specific type
   * `event: message` It will not trigger on any
   * other event type.
   */
  sse.addEventListener("message", function(e) {
    console.log(e.data)
  })

压缩图片方案解析

// 生成 input标签
var input = document.createElement("input");
input.type = "file";
input.id = "upload";
input.accept = "image/jpeg,image/png,image/bmp,image/gif";

// 压缩第一步
input.addEventListener("change", (e) => {
  //获取文件
  const file = e.target.files[0];
  // 生成FileReader实例
  const reader = new FileReader();
  // 将 File 对象通过 FileReader 的 readAsDataURL 方法转换为URL格式的字符串(base64编码)。
  reader.readAsDataURL(file);
  reader.onload = (theFile) => {
    // 生成图片类
    const image = new Image();
    // 设置图片标签src属性
    image.src = theFile.target.result;
    image.onload = () => {
        const fileForUpload = convertBase64toFile(processImg(image));
        // 最终压缩完成的file图片
        console.log(fileForUpload,'====')
    };
  };
});

// 第二步

const processImg = (img, quality = 0.7, wh = 1000) => {
  if (!img) {
    return;
  }

  // 生成canvas
  const canvas = document.createElement("canvas");
  // 返回一个用于在画布上绘图的环境。
  const ctx = canvas.getContext("2d");

  let height = img.height;
  let width = img.width;
  let imgWH = 1000;

  if (wh && wh < 1000 && wh > 0) {
    imgWH = wh;
  }

  // 按比例缩小图片
  if (width > imgWH || height > imgWH) {
    const ratio = Math.floor((height / width) * 10) / 10;
    if (width > height) {
      width = imgWH;
      height = imgWH * ratio;
    } else {
      height = imgWH;
      width = height / ratio;
    }
    img.width = width;
    img.height = height;
  }

  canvas.width = width;
  canvas.height = height;

  ctx.fillStyle = "#fff";
  ctx.fillRect(0, 0, width, height);
  // // 在画布上绘制图像
  ctx.drawImage(img, 0, 0, width, height);
  // 调用 canvas 的 toDataURL 方法可以输出 base64 格式的图片。
  return canvas.toDataURL("image/jpeg", quality);
};

// 第三步
const convertBase64toFile = (base64) => {
  const date = new Date().valueOf();
  const imageName = date + ".jpg";
  const imageBlob = dataURItoBlob(base64);

  // 第四步 输出file传给后台上传
  const imageFile = new File([imageBlob], imageName, { type: "image/jpg" });
  return imageFile;
};

// 仍是第三步哈哈哈 将base64的uri专为blob文件格式
// 这段我也不是很懂 设计比较底层的转码
const dataURItoBlob = (dataURI) => {
  // window.atob() 方法用于解码使用 base-64 编码的字符串。
  const byteString = atob(dataURI.split(",")[1]);
  const mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
  const arrayBuffer = new ArrayBuffer(byteString.length);
  const int8Array = new Uint8Array(arrayBuffer);
  for (let i = 0; i < byteString.length; i++) {
    int8Array[i] = byteString.charCodeAt(i);
  }
  const blob = new Blob([int8Array], { type: "image/jpg" });
  return blob;
};

blob

Blob 对象表示一个不可变、原始数据的类文件对象。Blob 表示的不一定是JavaScript原生格式的数据。File 接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。

Blob(blobParts[, options])

File

new File( Array parts, String filename, BlobPropertyBag properties);