最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS前端畫布與組件元信息數(shù)據(jù)流示例詳解

 更新時間:2023年02月06日 14:21:41   作者:黃子毅  
這篇文章主要為大家介紹了JS前端畫布與組件元信息數(shù)據(jù)流示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

接下來需要解決兩個問題:

  • 可視化搭建的其他業(yè)務元素如何與畫布交互。比如拓展屬性配置面板、圖層列表、拖拽添加組件、定位錨點、主題等等。
  • runtimeProps 如何訪問到當前組件實例的 props

這兩個問題非常重要,而恰好又可以通過良好的數(shù)據(jù)流設計一次性解決,接下來讓我們分別分析討論一下。

問題一:可視化搭建的其他業(yè)務元素如何與畫布交互。比如拓展屬性配置面板、圖層列表、拖拽添加組件、定位錨點、主題等等

需要設計一個 Hooks API,可以訪問到畫布提供的方法、數(shù)據(jù)。在 React 設計中,訪問 Hooks API 需要在一定上下文內,所以可以將 <Designer> 拆為 <Designer><Canvas>,其中 <Designer> 提供 Hooks 上下文,<Canvas> 負責渲染畫布。這樣開發(fā)者的使用方式就變成了這樣:

import { createDesigner } from 'designer'
const { Designer, Canvas, useDesigner } = createDesigner()
const EditPanel = {
  const { addComponent } = useDesigner()
  return <button onClick={() => addComponent(/** ... */)}>創(chuàng)建組件</button>
}
const App = () => {
  <Designer>
    <Canvas />
    <EditPanel />
  </Designer>
}

為了支持多個 Designer 實例間隔離,通過 createDesigner 創(chuàng)建一套上下文獨立的 API,這樣就可以讓畫布、配置面板同時用 Designer 實現(xiàn),用一套技術方案同時實現(xiàn)畫布與配置表單,這樣學習上下文、組件規(guī)范都可以統(tǒng)一為一套,表單、畫布能力也可以共享。

<Designer> 內的組件可以通過 useDesigner 直接訪問數(shù)據(jù)與方法,比如上面例子在直接訪問內置方法 addComponent 時,不需要附加任何參加,而 addComponent 方法也永遠保持引用不變,此時 useDesigner 不會導致 EditPanel 重渲染。

如果需要訪問當前組件樹,并在組件樹變化時重渲染,可以通過如下方式訪問:

const EditPanel = {
  const { componentTree } = useDesigner(state => ({
    componentTree: state.componentTree
  }))
}

該寫法的效果是,當 state.componentTree 變化了,會觸發(fā) EditPanel 重新渲染,并拿到最新值。

同時也可以傳入第二個參數(shù) compare 自定義對比方法,默認為 shallowEqual

useDesigner(
  (state) => ({
    componentTree: state.componentTree,
  }),
  isEqual
);

如此一來,無論給畫布拓展多少 UI 元素都沒有問題,而且 UI 元素可以自由的訪問畫布方法與數(shù)據(jù)。

問題二:runtimeProps 如何訪問到當前組件實例的 props

componentMeta.runtimeProps 中,我們構造一個 selector 函數(shù)用于訪問當前組件 props:

const divMeta = {
  componentName: "div",
  runtimeProps: ({ selector }) => {
    const name = selector(({ props }) => props.name)
    return {
      fullName: `full-${name}`
    }
  }
  element: /** ... */
};

首先支持從 runtimeProps 回調里拿到 selector,并且該 selector 支持傳入一個回調函數(shù),該回調函數(shù)的參數(shù)中 props 指向當前組件實例的 props,通過該方法就可以訪問組件 props 了。

該 selector 僅在 props.name 改變時重新執(zhí)行,并且也遵循 compare 對比規(guī)則,即當 props.name 變化時,selector 回調函數(shù)的返回值通過 compare 與上一次值進行對比,如果沒有變化就返回上一次的舊值,變化了則返回新值。默認對比函數(shù)為 shallowEqual,與 useDesigner 類似,也可以在第二個參數(shù)位置覆寫 compare 方法。

那組件元信息如何訪問內置靜態(tài)方法呢?由于靜態(tài)方法引用不變,因此可以在 selector 同級直接傳入:

const divMeta = {
  componentName: "div",
  runtimeProps: ({ addComponent }) => {
    return {
      add: () => {
        /** addComponent(...) */
      }
    }
  }
  element: /** ... */
};

如此一來,我們就將數(shù)據(jù)流與組件元信息打通了,即 UI 可以通過 useDesigner 訪問與操作數(shù)據(jù)流,組件元信息也可以直接拿到方法,或通過 selector 拿到數(shù)據(jù),相應的也可以訪問與操作數(shù)據(jù)流。這樣的設計在以后拓展更多組件元信息函數(shù)時,都可以繼承下來,開發(fā)者只要學習一次語法,就可以獲得非常強力的拓展性。

拓展應用狀態(tài)與靜態(tài)方法

剛才介紹了一些內置的狀態(tài)(componentTree)與方法(addComponent),在下一接會系統(tǒng)介紹筆者梳理了哪些內置狀態(tài)與方法。首先拋開內置狀態(tài)與方法不談,應用肯定需要定義自己的狀態(tài)與方法,我們可以提供兩種模式給用戶。

第一種是應用的狀態(tài)與方法定義在外部,對應受控模式。

假設你的應用在對接 Designer 之前就已經用 Redux、Dva、Zustand 等狀態(tài)管理庫,那么就可以使用受控模式直接接入:

const App = () => {
  // 偽代碼,不管是 useState 還是其他數(shù)據(jù)流管理狀態(tài),假這里拿到了數(shù)據(jù)與方法
  const { getAppInfo } = useSomeLib();
  const { userName } = useSomeLib("userName");
  return <Designer actions={{ getAppInfo }} state={{ userName }} />;
};

將方法傳給 actions,狀態(tài)傳給 state。

第二種是應用的狀態(tài)與方法通過 <Designer> 定義,對用非受控模式。

假設你的應用之前沒有使用任何數(shù)據(jù)流,那么也可以直接將 Designer 的數(shù)據(jù)流作為項目數(shù)據(jù)流使用:

import { createMiddleware, createDesigner } from "designer";
const middleware1 = createMiddleware({
  state: { userName: "bob " },
  actions: { getAppInfo: () => {} },
});
const { Designer } = createDesigner(middleware1);
const App = () => {
  return <Designer />;
};

通過 createMiddleware 創(chuàng)建一個中間件定義狀態(tài)與函數(shù),傳入 createDesigner 即可生效。

也可以在 createMiddleware 里通過第二個參數(shù)定義自定義 hooks,或者拿到方法更改 State:

const middleware1 = createMiddleware(
  {
    state: { userName: "bob " },
  },
  ({ setState }) => {
    const setUserName = React.useCallback((newName: string) => {
      setState((state) => ({
        ...state,
        userName: newName,
      }));
    });
    return { setUserName };
  }
);

Designer 內部采用最樸素的 Redux 管理狀態(tài),提供了最基礎的 getStatesetState 獲取與修改狀態(tài),基于它們封裝業(yè)務函數(shù)即可。

無論是受控模式,還是非受控模式(亦或兩種模式同時使用),定義的狀態(tài)與方法都可以在以下兩個位置訪問,第一個位置是 useDesigner

const {
  /** 自定義函數(shù) */,
  setUserName,
  /** 自定義函數(shù) */
  getAppInfo,
  /** 內置函數(shù) */
  addComponent,
  // 內置變量
  componentTree,
  // 自定義變量
  userNamee
} = useDesigner(state => ({
  componentTree: state.componentTree,
  userName: state.userName
}))

第二個位置是組件元信息上的回調函數(shù),比如 runtimeProps

const divMeta = {
  componentName: "div",
  runtimeProps: ({
    selector,
    /** 自定義函數(shù) */,
    setUserName,
    /** 自定義函數(shù) */
    getAppInfo,
    /** 內置函數(shù) */
    addComponent
   }) => {
    const {
      /** 內置變量 */
      componentTree,
      /** 自定義變量 */
      userName
    } = selector(({ state }) => ({
      componentTree: state.componentTree,
      userName: state.userName
    }))
    return { componentTree, userName }
  }
  element: /** ... */
};

至此,我們實現(xiàn)了一套完整的數(shù)據(jù)流定義,包括:

  • 不同 Designer 之間上下文隔離。
  • 可無縫對接項目數(shù)據(jù)流,也可作為獨立數(shù)據(jù)流方案提供。
  • 內置變量與函數(shù)與自定義變量、函數(shù)混合。
  • 無論在 UI 通過 useDesigner,還是在組件元信息通過 selector 都可訪問這些變量與函數(shù)。

總結

一個基本可用的可視化搭建框架在本章就算設計完了。但這只是可視化搭建問題的冰山一角,未來的章節(jié),筆者會逐漸為大家介紹更多可視化搭建的設計。

但無論框架未來怎么發(fā)展,也永遠會基于這前三章的基本設定,總結一下,這三章的基本設定就是:設計一個邏輯與 UI 分離的可視化搭建協(xié)議,數(shù)據(jù)流、組件元信息、組件實例是永遠的鐵三角,數(shù)據(jù)流可以對接任意已存在的實現(xiàn),或基于 Designer 規(guī)范實現(xiàn),組件元信息與組件實例僅存儲最基本信息,得益于數(shù)據(jù)流的自定義能力,以及無論何處都有完全的數(shù)據(jù)流訪問能力,使業(yè)務框架既遵循規(guī)則,又可以千變萬化。

拋開具體 API 設計或者命名不談,一個有簡潔、抽象,又提供極少量 API 卻能滿足所有業(yè)務定制訴求,是可視化搭建永遠追求的目標。只要熟悉了這套規(guī)范,就可以幾乎僅根據(jù)業(yè)務表現(xiàn),一眼猜出是基于哪些 API 封裝實現(xiàn)的,那么維護成本與理解成本將大大降低,規(guī)范的意義就體現(xiàn)在這里。

也許有同學會覺得,現(xiàn)在各個大廠都有無數(shù)可視化搭建的實現(xiàn),可視化搭建概念都已經爛大街了,為什么還要重新設計一個呢?

因為也許數(shù)量不代表質量,維護的時間越久,參與的同學越多,越容易使設計變得冗余,概念變得復雜,要對抗這些遞增的熵,唯有不斷重新設計,從零開始反思方案。

下一講理論思考會少一些,介紹可視化搭建框架會考慮內置哪些變量與方法,更多關于JS畫布與組件元信息數(shù)據(jù)流的資料請關注腳本之家其它相關文章!

版權聲明:自由轉載-非商用-非衍生-保持署名(創(chuàng)意共享 3.0 許可證

相關文章

  • 微信小程序 template模板詳解及實例

    微信小程序 template模板詳解及實例

    這篇文章主要介紹了微信小程序 template模板詳解及實例的相關資料,需要的朋友可以參考下
    2017-02-02
  • JavaScript內置對象介紹

    JavaScript內置對象介紹

    這篇文章主要介紹了JavaScript內置對象,內置對象就是指?JS?語言自帶的一些對象,這些對象供開發(fā)者使用,并提供了一些常用的或是最基本而必要的功能,下面我們一起進入文章了解更多詳細內容
    2021-12-12
  • 深入淺出探究JavaScript中的async與await

    深入淺出探究JavaScript中的async與await

    任意一個名稱都是有意義的,先從字面意思來理解。async 是“異步”的簡寫,而 await 可以認為是 async wait 的簡寫。所以應該很好理解 async 用于申明一個 function 是異步的,而 await 用于等待一個異步方法執(zhí)行完成。下文將帶你深入探究JavaScript中的async與await
    2021-09-09
  • 判斷Spartacus?SSR的Transfer?State是否正常工作技巧

    判斷Spartacus?SSR的Transfer?State是否正常工作技巧

    這篇文章主要為大家介紹了判斷Spartacus?SSR的Transfer?State是否正常工作技巧,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • 微信小程序 slider 詳解及實例代碼

    微信小程序 slider 詳解及實例代碼

    這篇文章主要介紹了微信小程序 slider 詳解及實例代碼的相關資料,需要的朋友可以參考下
    2017-01-01
  • 前端的狀態(tài)管理(下)

    前端的狀態(tài)管理(下)

    這篇文章主要介紹了前端的狀態(tài)管理,續(xù)上篇文章內容,今天將從 Redux 入手逐漸拓展,需要的小伙伴可以參考一下喲
    2021-10-10
  • 微前端下element-ui彈框偏移問題解決

    微前端下element-ui彈框偏移問題解決

    本章主要是解決無界微前端環(huán)境下element-ui彈框偏移問題,如果你用的是其他微前端框架,且提供了jsloader這種預處理器,則可以舉一反三解決同樣的問題
    2023-08-08
  • JS輕量級函數(shù)式編程實現(xiàn)XDM二

    JS輕量級函數(shù)式編程實現(xiàn)XDM二

    這篇文章主要為大家介紹了JS函數(shù)式編程實現(xiàn)XDM示例詳解第2/3篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Fabric.js 拖拽平移畫布方法示例

    Fabric.js 拖拽平移畫布方法示例

    這篇文章主要為大家介紹了Fabric.js 拖拽平移畫布方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • 微信小程序 wx.request方法的異步封裝實例詳解

    微信小程序 wx.request方法的異步封裝實例詳解

    這篇文章主要介紹了微信小程序 wx.request方法的異步封裝實例詳解的相關資料,需要的朋友可以參考下
    2017-05-05

最新評論

白山市| 龙里县| 株洲县| 柯坪县| 鹤峰县| 麦盖提县| 佳木斯市| 利辛县| 黎川县| 昔阳县| 铜山县| 页游| 阿克陶县| 稻城县| 东乡县| 射阳县| 黄大仙区| 沙坪坝区| 平南县| 临清市| 诸暨市| 勐海县| 武强县| 上犹县| 云南省| 泸溪县| 张掖市| 兴化市| 昌邑市| 武宣县| 万盛区| 车险| 伊宁县| 新沂市| 枣阳市| 北海市| 广安市| 林州市| 凌海市| 衡水市| 安多县|