Ts + React + Mobx реализуют консоль мобильного браузера

React.js MobX
Ts + React + Mobx реализуют консоль мобильного браузера

С тех пор, как я начал использовать Typescript для написания мини-игр H5, я полагался на Ts (интеллектуальные подсказки и дружественные подсказки по рефакторингу), но из-за егоType SystemНеобходимо больше практики.

Недавно разработанные мини-игры H5, с точки зрения мобильной отладки, режим проверки не используется для удобства. используется грубоvConsole, вы должны научиться быть благодарным за чужие вещи, поэтому я решил понять его принцип и, наконец, использовать Ts + React для кодирования одногоКонсоль мобильного браузера, бытьTs+React в действии.

С помощью этого урока вы можете узнать:

  • Процесс разработки Ts + React + Mobx
  • Базовая система типов
  • Некоторые основные концепции JavaScript
  • Знание консоли браузера
    • Console
    • Сеть, XHR
    • Storage
    • Основной код рендеринга DevTool

Исходный код проектаВпервые используя проект кода Typescript + React,Запишите итерационный процесс, если вам интересно зайти в яму, можете поставить звездочкуС нетерпением жду CodeReview.

Начинать

В соответствии с концепцией быстрого развития (хочу родить ребенка), на основеCreate React AppДля строительных проектов фреймворк пользовательского интерфейса использует тот же написано ЦAntMobile. Прежде чем приступить к объяснению проекта, очевидно, что вам необходимо иметь определенное представление об этих двух (предложения можно использовать в качестве справочного материала для дальнейшего изучения Ts + React).

Ниже давайте взглянем на превью изображения

Пользовательский интерфейс прост, разделен по функциям на

  • Журнал 、 Система
  • Network
  • Elemnet
  • Storage

В основном из вышеперечисленных функциональных модулей

PS: В туториале некоторые пропущены, например, как поддерживать стилус (проект выполнил yarn run eject ), добавлять ли I в интерфейс, делать публичный рендеринг или нет, как удалить некоторые Tslint и т. д. (отслеживание истории файла git может быть малоизвестно) PWA и т. д.

базовый стиль кода

Я буду писать компоненты в этом стиле (не лучшая практика) на протяжении всей этой статьи (меньше компонентов без состояния и без применения компонентов более высокого порядка).

import React, { Component } from 'react';

interface Props {
  // props type here
}

interface State {
  // state type here
}

export default class ClassName extends Component<Props, State> {
  // state: State = {...}; 我更喜欢将 state 写在这。

  constructor(props: Props) {
    super(props);
    this.state = {
      // some state
    };
  }

  // some methods...

  render() {
    // return
  }
}

Log

Наиболее часто используемая консоль отладки — Log, а неотъемлемый API —window.console['log', 'info', 'warn', 'debug', 'error']

consolewindow.consoleconsole

const methodList = ['log', 'info', 'warn', 'debug', 'error'];

methodList.map(method => {
  // 1. 保存 window 自带 console 方法。
  this.console[method] = window.console[method];
});

methodList.map(method => {
  window.console[method] = (...args: any[]) => {
    // 2. 做一些保存数据及展示的操作。

    // 3. 调用原生 console 方法。
    this.console[method].apply(window.console, infos);
  };
});

console.log(参数)

import { observable, action, computed } from 'mobx';

export interface LogType {
  logType: string;
  infos: any[]; // 来自 console 方法的参数。
}

export class LogStore {
  @observable logList: LogType[] = [];
  @observable logType: string = 'All';

  // some action...
}

export default new LogStore();

logView

key-value

__proto__functionlog()

Objectkey-valueArray

<li className="my-code-wrap">
  <div className="my-code-box">
    // 1. 判断是否需要显示展开图标
    {opener}
    <div className="my-code-key">
      // 2. 显示 key
      {name}
    </div>
    <div className="my-code-val">
      // 3. 根据值类型,选择其展示方式
      {preview}
    </div>
  </div>
  // 4. 如果是 Object 或 Array,则重复 1.
  {children}
</li>

  sendCMD() {
    return (cmd: string) => {
      let result = void 0;
      try {
        result = eval.call(window, '(' + cmd + ')');
      } catch (e) {
        try {
          result = eval.call(window, cmd);
        } catch (e) {
          ;
        }
      }
      // mobx中的 action
      logStore.addLog({ logType: 'log', infos: [result] })
    }
  }

eval()

winodw.consolescript errorfundebug

System

userAgent

network

Network

networkXMLHttpRequest

opensendgetAllResponseHeadersonreadystatechangereadyStatestatusresponse

onreadystatechange

XMLHttpRequest.readyStateXMLHttpRequest

0 UNSENT
1 OPENED
2 HEADERS_RECEIVED
3 LOADING
4 DONE

  mockAjax() {
    // 这里的 (window as any).XMLHttpRequest 我用的很虚。太粗暴了
    const XMLHttpRequest = (window as any).XMLHttpRequest;
    if (!XMLHttpRequest) {
      return;
    }
    const that = this;
    // 1、备份原生 XMLHttpRequest 的 open 和 send 方法
    const XHRnativeOpen = XMLHttpRequest.prototype.open;
    const XHRnativeSend = XMLHttpRequest.prototype.send;

    // 2、重写 open 方法
    XMLHttpRequest.prototype.open = function (...args: any) {
      // 3、获取 open 方法传入的参数
      const [method, url] = args;

      // 4、保存原有  onreadystatechange
      const userOnreadystatechange = this.onreadystatechange;

      this.onreadystatechange = function (...stateArgs: any) {
        // do something

        // 5、根据 readyState 做相应处理,主要是保存需要展示的数据,比如 response 和 header

        // 6、调用原有 onreadystatechange
        return (
          userOnreadystatechange &&
          userOnreadystatechange.apply(this, stateArgs)
        );
      };

      // 7、调用原生 XMLHttpRequest.open 方法
      return XHRnativeOpen.apply(this, args);
    };
    XMLHttpRequest.prototype.send = function (...args: any) {
      // 8、重写 XMLHttpRequest.send 方法并保存数据
      return XHRnativeSend.apply(this, args);
    };
  }

prototypeXMLHttpRequestaxiosXMLHttpRequestfetch

Element

document.documentElement

DOM Node

nodeType

<body style="background:#000"></body><img src="...">

htmlView


import { parseDOM } from 'htmlparser2';

// 1. 将 HTML 文本,解析为 JSON 格式
const tree = parseDOM(document.documentElement.outerHTML);


// 2. 转换为易于展示的 JSON 格式,并转换为 Immutable 数据

  getRoot() {
    const { tree, defaultExpandedTags } = this.props;

    transformNodes(tree, [], true);
    return Immutable.fromJS(tree[0]);

    function transformNodes(trees: any[], keyPath: any, initial?: boolean) {
      trees.forEach((node: any, i: number) => {
        // 3. 数据转换逻辑
      });
    }
  }

// 3. 根据 type 来区分渲染 UI

if (type === 'text' || type === 'comment') {

}

htmlparser2demohtmlparser2

Storage

localstoragecookies

Ts + React + Mobx

// Ts 让代码更加易于阅读,只需要看组件这部分代码即可知道,
// 组件接受哪些属性以及其内部状态,并且可以知道他们都接受什么样的类型。

interface Props {
  togglePane: () => void;
  logList: LogType[]
}

interface State {
  searchVal: string
}

// 组件泛型
export default class ClassName extends PureComponent<Props, State> {
  // ...
}

Type definitions

  "devDependencies": {
    "@types/jest": "^23.3.9",
    "@types/node": "^10.12.5",
    "@types/react": "^16.7.2",
    "@types/react-dom": "^16.0.9",
    "typescript": "^3.1.6"
  }
// 获取 ref 上有所不同
export default class Log extends Component<Props, State> {
  private searchBarRef = createRef<SearchBar>()
  sendCMD = ()=> {
      this.searchBarRef.current!.focus()
  }
  render() {
    return (
      <Flex>
        <SearchBar
          ref={this.searchBarRef}
          onclic={this.sendCMD}
        />
      </Flex>
    );
  }
}

yarn run eject

package.json

{
  "scripts": {
    "eject": "react-scripts eject"
  }
}