主頁 > 企業開發 > 用 rollup + gulp 造個輪子,別說還挺香

用 rollup + gulp 造個輪子,別說還挺香

2022-04-03 07:49:24 企業開發

前戲

我是16年入了前端的坑,17年知道了gulprollup這兩個玩意兒,由于那時webpack勢頭很猛,便一直沒有正眼瞧過它一眼,

直到20年進了一家小公司,做了很多類似的小專案,相同的代碼拷來拷去,出現一個bug一堆專案都要改,實在惡心到我了,

于是不得不開始考慮將一些公共的方法和組件提取出來,做成一個第三方庫來維護,而在庫的封裝方面,rollup相對于webpack具有一定的優勢,

在此,便和大家分享一下如何自己造輪子,封裝一個前端庫并發布到npm倉庫中去,

原始碼

這是我自己封裝的3個庫,有興趣可以看看:

https://github.com/moohng/dan;

https://github.com/moohng/dui;

https://github.com/moohng/tui;

第一個是工具函式庫,后面兩個是UI庫,目前已全部使用TypeScript重寫,dui是基于Vue 3封裝的,tui無任何依賴,通過tsx語法實作的,

由于后面沒多久就離職了,也就沒有封裝更多方法和組件進去了,但還是具有一定的學習參考價值,尤其對于新手朋友,

每一個庫從目錄結構、打包命令、匯出方式、ts型別支持、單元測驗、自動發布等,幾乎所有細節知識都涵蓋到了,

實操

瀏覽百遍,不如實操一遍(文章基于tui來做介紹),

目錄結構

tui專案原始碼的目錄結構

另外,還有libdist兩個打包輸出的目錄沒有列出來,

從上到下:

  • .github:GitHub自動打包發布的腳步配置目錄;
  • packages:存放tui組件庫的原始碼;
  • src:tui組件庫演示demo目錄;
  • test:測驗相關代碼;
  • webpack:暫時忽略,用于測驗webpack打包用的;

后面的babel.config.jsongulpfile.esm.jsrollup.config.jstsconfig.json分別是babelgulprollupts的組態檔,

環境配置

tsconfig.json配置如下:

{
  "compilerOptions": {
    "jsx": "preserve", // 支持jsx
    "module": "esnext",
    "target": "esnext",
    "declaration": true, // 生成相應的 .d.ts檔案
    "declarationDir": "lib", // 生成宣告檔案的輸出路徑
    "noEmitOnError": true,
    // "strict": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictNullChecks": true,
    "strictPropertyInitialization": true,
    "skipLibCheck": true,
    "moduleResolution": "node"
  },
  "include": ["packages/**/*"],
}

在組態檔中,需要開啟jsx的支持,因為tui的html是基于jsx語法來實作的;同時啟用生成.d.ts檔案功能,這個功能可以在ts編譯的時候根據我們的原始碼自動生成.d.ts型別宣告檔案,

babel的配置相對要復雜一些,主要是對tsx的支持上,

部分配置原始碼如下:

{
  "presets": [
    "@babel/preset-env",
    [
      "@babel/preset-react",
      {
        "pragma": "Tan.createElement", // 類似于 React.createElement 方法
        "pragmaFrag": "Tan.Fragment", // 類似于 React.Fragment 片段
        "importSource": false,
        "useSpread": true
      }
    ],
    [
      "@babel/preset-typescript",
      {
        "isTSX": true,
        "jsxPragma": "Tan",
        "allExtensions": true
      }
    ]
  ]
}
  • @babel/preset-react:用于決議jsx語法,生成Tan.createElement('div', {})這種js函式結構;
  • @babel/preset-typescript:將ts轉成js,替代tsc命令;

組件的實作

以最簡單的Toast組件為例,

功能:

  • 提供通用、成功、失敗、通知、警告、加載中等幾種狀態;
  • 支持上、下、居中等位置彈出;
  • 支持普通呼叫和快捷呼叫多種呼叫方式;

組件結構設計(非完整代碼):

// packages/Toast/index.tsx

/** 組件入參 */
interface ToastOptions {
  text?: string; // 字串 或 html模板
  type?: 'success' | 'error' | 'info' | 'warn' | 'loading' | 'toast';
  margin?: string;
  duration?: number;
  position?: 'top' | 'bottom' | 'center';
}

/** 組件物件(支持函式呼叫和快捷方式呼叫) */
interface ToastObject {
  (options: string | ToastOptions): ToastHide;
  info: ToastFunction;
  success: ToastFunction;
  error: ToastFunction;
  warn: ToastFunction;
  loading: ToastFunction;
}

interface ToastFunction {
  (text: string): ToastHide;
}

interface ToastHide {
  (): void;
}

/** 函式實作 */
const Toast: ToastObject = (options) => {
  // ...
}

/** 組件匯出 */
Toast.info = (text: string) => Toast({ text, type: 'info' });
Toast.success = (text: string) => Toast({ text, type: 'success' });
Toast.error = (text: string) => Toast({ text, type: 'error' });
Toast.warn = (text: string) => Toast({ text, type: 'warn' });
Toast.loading = (text: string = '正在加載') => Toast({ text, type: 'loading' });

export default Toast;

組件結構有了,現在主要就是Toast函式的實作了,

開始無外乎就是對引數的判斷,然后就是生成對應的DOM結構,最后插入到真實的DOM檔案中去,

這里主要說一下jsx的實作,下面是Toast組件的jsx原始碼:

// 創建 DOM
let $toast = options.type === 'loading' ? (
  <>
    <div className="mask loading"></div>
    <div className="tui-toast" dataType={options.type} dataPosition={options.position}>
      <i className="tui-icon__loading"></i>
      <span>{options.text ?? ''}</span>
    </div>
  </>
) : <div className="tui-toast" dataType={options.type} dataPosition={options.position}>{options.text ?? ''}</div>;

是不是看起來跟React很像?沒錯,這就是我們需要的,

還記得上面babel中配置的Tan.createElement嗎?它就是為了將我們這里的jsx語法轉成Tan.createElement的函式形式,

看看編譯后的代碼(部分):

Tan.createElement(
  Tan.Fragment,
  null,
  Tan.createElement('div', {
    className: 'mask loading',
  }),
  Tan.createElement(
    'div',
    {
      className: 'tui-toast',
      dataType: options.type,
      dataPosition: options.position,
    },
    Tan.createElement('i', {
      className: 'tui-icon__loading',
    }),
    Tan.createElement(
      'span',
      null,
      (_options$text = options.text) !== null && _options$text !== void 0 ? _options$text : ''
    )
  )
)

其實React也是一樣,它也是通過babel將jsx語法轉成了React.createElement函式形式,同樣的,我們也可以將React.createElement換成我們自己實作的函式,jsx并非React獨有,Vue同樣也支持,誰都可以使用,關鍵在于如何轉換的問題,

Tan.createElement 的實作

我實作的比較簡單,一共也才幾十行代碼,滿足一些基本常用的語法,

全部原始碼如下:

// packages/core/index.ts
import { flat } from '@moohng/dan';

interface FragmentTag {
  Fragment: DocumentFragment;
}

type TagMap = HTMLElementTagNameMap & FragmentTag;

function createFragment() {
  return document.createDocumentFragment();
}

export const Fragment: keyof FragmentTag = 'Fragment';

const hasOwnProperty = Object.prototype.hasOwnProperty;
const toString = Object.prototype.toString;

function classnames(className: string | Record<string, boolean> | (Record<string, boolean> | string)[]): string[] {
  if (typeof className === 'string') {
    const splitter = /\s+|\s*,\s*/;
    return className.split(splitter).filter(item => item);
  }
  if (Array.isArray(className)) {
    const r: string[] = [];
    className.forEach(item => {
      r.push.apply(r, classnames(item));
    });
    return r;
  }
  if (toString.call(className) === '[object Object]') {
    return classnames(Object.keys(className).filter(item => className[item]));
  }
  return [];
}

export function createElement<K extends keyof TagMap>(node: K | TagMap[K] | HTMLElement, props?: Record<string, unknown>, ...children: (HTMLElement | string | HTMLElement[] | string[])[]) {
  // 創建 DOM
  if (typeof node === 'string') {
    if (node === Fragment) {
      (node as unknown as DocumentFragment) = createFragment();
    } else {
      node = document.createElement(node);
    }
  }
  // 設定屬性
  props && Object.keys(props).forEach(key => {
    // 如果是 on 開頭,則為事件監聽
    const eventType = key.match(/^on(\w+)$/)?.[1];
    if  (eventType && typeof props[key] === 'function') {
      (node as TagMap[K]).addEventListener(eventType.toLocaleLowerCase(), props[key] as EventListenerOrEventListenerObject, false);
    } else if (key === 'style' && typeof props[key] !== 'string') {
      const style = props[key] as any
      for (const k in style) {
        if (hasOwnProperty.call(style, k)) {
          (node as HTMLElement).style[k] = style[k];
        }
      }
    } else if (key === 'className') {
      const className = classnames(props[key] as any);
      (node as HTMLElement).classList.add.apply((node as HTMLElement).classList, className);
    } else {
      const _key = key.replace(/[A-Z0-9]/g, v => '-' + v.toLocaleLowerCase());
      if ((node as any).setAttribute) {
        (node as HTMLElement).setAttribute(_key, props[key] as string || '');
      }
    }
  });
  // 添加子節點
  const childNodes = flat(children.filter(item => item || typeof item === 'number'));
  (node as TagMap[K]).append.apply((node as TagMap[K]), childNodes as Node[])

  return node;
}

createElement 函式很簡單,主要就是創建DOM節點,正確的決議props引數,

有了createElement,只需要在對應的jsx檔案中引入就行了,

import * as Tan from '../core/index';

這也是為什么React組件都需要在檔案頭部引入import * as React from 'react';的原因,

編譯打包

先看package.json中定義的scripts

"scripts": {
  "serve": "parcel serve index.html --dist-dir build/cache --no-cache",
  "build:css": "gulp css",
  "build:types": "tsc --emitDeclarationOnly",
  "build:es": "babel packages -d es -x \".ts,.tsx\" --env-name es",
  "build:lib": "babel packages -d lib -x \".ts,.tsx\"",
  "build:dist": "rollup -c",
  "build": "npm run build:types && npm run build:es && npm run build:lib && npm run build:dist && npm run build:css",
  "type-check": "tsc --noEmit",
  "test": "jest"
},
  • tsc --emitDeclarationOnly命令就是生成.d.ts檔案;
  • babel packages -d lib -x \".ts,.tsx\"命令就是將packages目錄中的組件編譯到lib目錄;

通過這兩條命令組件的js部分就算是搞定了,

組件的css樣式我是放在全域的,其實大部分的UI框架的樣式檔案也都是在全域定義的,這跟我們開發專案不同,

樣式的編譯,其實也就是將scss轉成css和一些其他轉換、壓縮等操作,這里,我是通過gulp將這些操作組合起來的,

gulpfile.esm.js部分配置原始碼:

import { src, dest, parallel } from 'gulp';

import sass from 'gulp-sass';
import postCSS from 'gulp-postcss';
import autoprefixer from 'autoprefixer';

export function css_lib(cb) {
  src(['packages/**/style/*.scss'], {
    base: 'packages',
  })
    .pipe(sass({
      outputStyle: 'expanded',
    }))
    .pipe(postCSS([autoprefixer()]))
    .pipe(dest('lib'));

  cb();
}

到這里為止,我們的組件庫的lib輸出目錄就算完成了,lib目錄主要是為了方便我們對單個組件的引入,但通常,一個組件庫還需要支持script標簽引入(一次性引入),

所以我們還需要將所有的組件庫代碼進行打包,提到打包,rollup便就派上用場了,

// rollup.config.js
import path from 'path';
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import { terser } from 'rollup-plugin-terser';

const extensions = ['.js', '.jsx', '.ts', '.tsx'];

module.exports = {
  input: path.resolve('packages/index.ts'),
  plugins: [
    resolve({ extensions }),
    babel({
      extensions,
      include: ['packages/**/*'],
    }),
  ],
  output: [
    {
      file: 'dist/tui.js',
      format: 'umd',
      name: 'tui',
      // https://rollupjs.org/guide/en#output-globals-g-globals
      globals: {},
    },
    {
      file: 'dist/tui.min.js',
      format: 'umd',
      name: 'tui',
      // https://rollupjs.org/guide/en#output-globals-g-globals
      globals: {},
      plugins: [
        terser(),
      ],
    },
  ],
};

這個就和我們開發專案時用的webpack打包工具一樣,可以指定匯出方式,以及對代碼進行壓碩訓淆,

到這里,一個基本的UI庫才算完成,

注意打包和編譯的概念,編譯僅僅是通過babel或sass將原始碼轉換成瀏覽器能支持的js或css代碼;而打包是在編譯的基礎之上,再將源檔案進行整合,輸出一個或多個檔案,rollup和webpack一樣,都是打包工具,gulp是任務(流程)管理工具,

單元測驗

最后,還有“不那么重要”的測驗,

說實話,自己設計組件自己寫的代碼然后自己寫測驗,有點像“脫褲子放屁——多此一舉”了,也許是我對測驗的理解還不夠深入吧,畢竟大佬們都說測驗有多重要,咱不懂、咱也不敢問,暫且裝模作樣地寫上吧,

測驗框架選用的是jest,據說是很強大的東西,

在專案根目錄下創建一個test目錄,里面寫的測驗檔案以.test.ts后綴命名,測驗的時候就可以自動執行了,

比如(部分原始碼):

// createElement.test.tsx
import * as Tan from '../lib/core';

test('jsx', () => {
  const text = 'Hello World';
  const handleClick = (e: MouseEvent) => {
    (e.target as HTMLDivElement).innerText = '你好';
  }
  const test = <div dataType="success" onClick={handleClick}>{text}</div>;

  expect(test.textContent).toBe(text);
  expect(test.getAttribute('data-type')).toBe('success');

  test.click();
  expect(test.innerText).toBe('你好');
});
// import { Toast } from '../lib';
import { Toast } from '../lib';

test('toast loading', done => {
  const text = '玩命加載中...';
  const hide = Toast.loading(text);

  expect(document.querySelector('.tui-toast span').textContent).toBe(text);
  setTimeout(() => {
    hide();
    setTimeout(() => {
      expect(document.querySelector('.tui-toast')).toBeNull();
      expect(document.querySelector('.mask')).toBeNull();
    }, 100);
    done();
  }, 1000);
});

自動發布

如果每次提交代碼后,會自動發布到npm倉庫,是不是省了很多事兒,以前,這種事大多都是通過Travis CI去做的,不過現在,Github本身就支持該功能了,是不是很贊,

# .github/workflows/npmpublish.yml
name: npm

on:
  release:
    types: [created]

jobs:
  publish-npm:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
        with:
          node-version: 12
          registry-url: https://registry.npmjs.org/
      - run: yarn --frozen-lockfile
      - run: yarn build
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{secrets.npm_token}}

上面這個配置就是在每次創建一個release版本的時候,會自動將我們的代碼編譯打包,發布到npm倉庫中去,需要提前配置好NODE_AUTH_TOKEN變數,npm_token可以去npm平臺獲取,然后在GitHub倉庫的Settings里面配置就行了,

完事

如果你喜歡造輪子,這篇文章應該會對你有幫助,這是我踩了很多坑才摸索出來的,文章只能說個大概流程,強烈建議去GitHub上看原始碼,

最后,歡迎去我的公眾號【末日碼農】,獲取更多技術知識,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/455431.html

標籤:JavaScript

上一篇:都知道0.1+0.2 = 0.30000000000000004,那要怎么讓它等于0.3

下一篇:HTML第二天

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more