100202Title和Input組件_編輯器-react-仿低代碼平臺項目

文章目錄

    • 1 開發兩個問卷組件
      • 1.1 Title組件
      • 1.2 Input組件
      • 1.3 畫布靜態展示TItle和Input
    • 2 Ajax獲取問卷數據,并存儲到Redux store
      • 2.1 API接口
      • 2.2 組件列表存儲到Redux store統一管理
      • 2.3 重構useLoadQuestionData
    • 3 在畫布顯示問卷列表,點擊可選中
      • 3.1 Redux獲取組件列表
      • 3.2 根據Redux組件列表渲染組件
      • 3.3 點擊選擇組件,共享selectedId
    • 關于

1 開發兩個問卷組件

1.1 Title組件

數據類型和默認值,interface.ts代碼如下:

export type QuestionTitlePropsType = {text?: string;level?: 1 | 2 | 3 | 4 | 5;isCenter?: boolean;
};export const QuestionTitleDefaultProps: QuestionTitlePropsType = {text: "一行標題",level: 1,isCenter: false,
};

組件Component.tsx代碼如下所示:

import { FC } from "react";
import { Typography } from "antd";
import { QuestionTitlePropsType, QuestionTitleDefaultProps } from "./interface";const { Title } = Typography;const QuestionTitle: FC<QuestionTitlePropsType> = (props: QuestionTitlePropsType,
) => {const {text = "",level = 1,isCenter = false,} = { ...QuestionTitleDefaultProps, ...props };const genFontSize = (level: number) => {if (level === 1) {return "24px";} else if (level === 2) {return "20px";} else if (level === 3) {return "16px";} else if (level === 4) {return "12px";} else {return "16px";}};return (<Titlelevel={level}style={{textAlign: isCenter ? "center" : "start",marginBottom: "0",fontSize: genFontSize(level),}}>{text}</Title>);
};export default QuestionTitle;

1.2 Input組件

數據類型和默認值,interface.ts代碼如下:

export type QuestionInputPropsType = {title?: string;placeholder?: string;
};export const QuestionInputDefaultProps: QuestionInputPropsType = {title: "輸入框標題",placeholder: "請輸入...",
};

組件Component.tsx代碼如下所示:

import { FC } from "react";
import { Typography, Input } from "antd";
import { QuestionInputPropsType, QuestionInputDefaultProps } from "./interface";const { Paragraph } = Typography;const QuestionInput: FC<QuestionInputPropsType> = (props: QuestionInputPropsType,
) => {const { text = "", placeholder = "" } = {...QuestionInputDefaultProps,...props,};return (<div><Paragraph strong>{text}</Paragraph><div><Input placeholder={placeholder}></Input></div></div>);
};export default QuestionInput;

1.3 畫布靜態展示TItle和Input

組件EditCanvas.tsx代碼如下:

import { FC } from "react";
import styles from "./EditCanvas.module.scss";import { Spin } from "antd";import QuestionTitle from "@/components/QuestionComponents/QuestionTitle/Component";
import QuestionInput from "@/components/QuestionComponents/QuestionInput/Component";type PropsType = {loading: boolean;
};const EditCanvas: FC<PropsType> = ({ loading }) => {if (loading) {return (<div style={{ textAlign: "center", marginTop: "24px" }}><Spin /></div>);}return (<div className={styles.canvas}><div className={styles["component-wrapper"]}><div className={styles.component}><QuestionTitle /></div></div><div className={styles["component-wrapper"]}><div className={styles.component}><QuestionInput /></div></div></div>);
};export default EditCanvas;

樣式EditCanvas.module.scss代碼如下:

.canvas {min-height: 100%;background-color: #fff;overflow: hidden;
}.component-wrapper {margin: 12px;border: 1px solid #fff;padding: 12px;border-radius: 3px;&:hover {border-color: #d9d9d9;}
}.component {pointer-events: none; // 屏蔽鼠標行為,組件不讓被點擊到
}

效果如下圖所示:

在這里插入圖片描述

2 Ajax獲取問卷數據,并存儲到Redux store

2.1 API接口

獲取問卷詳情API接口如下:

{// 獲取問卷信息url: '/api/question/:id',method: 'get',response() {return {errno: 0,data: {id: Random.id(),title: Random.ctitle(),componentList: [{fe_id: Random.id(),type: 'questionTitle',title: '標題',props: {text: '個人信息調研',level: 1,isCenter: false}},{fe_id: Random.id(),type: 'questionInput',title: '輸入框',props: {text: '你的姓名',placeholder: '請輸入姓名...',}},{fe_id: Random.id(),type: 'questionInput',title: '輸入框',props: {text: '你的電話',placeholder: '請輸入電話...',}},]},}}}

2.2 組件列表存儲到Redux store統一管理

src/store/componentsReducer/index.ts代碼如下:

import { createSlice, PayloadAction } from "@reduxjs/toolkit";import { ComponentPropsType } from "@/components/QuestionComponents";export type ComponentInfoType = {fe_id: string;type: string;title: string;props: ComponentPropsType;
};export type ComponentsStateType = {componentList: Array<ComponentInfoType>;
};const INIT_STATE: ComponentsStateType = {componentList: [],// 其他擴展
};export const componentsSlice = createSlice({name: "components",initialState: INIT_STATE,reducers: {// 重置所有組件resetComponents(state: ComponentsStateType,action: PayloadAction<ComponentsStateType>,) {return action.payload;},},
});export const { resetComponents } = componentsSlice.actions;
export default componentsSlice.reducer;

組件屬性類型src/components/QuestionComponents/index.ts代碼如下:

import { FC } from "react";import QuestionInputConf, { QuestionInputPropsType } from "./QuestionInput";
import QuestionTitleConf, { QuestionTitlePropsType } from "./QuestionTitle";// 各個組件屬性類型
export type ComponentPropsType = QuestionInputPropsType &QuestionTitlePropsType;// 統一組件配置
export type ComponentConfType = {title: string;type: string;Component: FC<ComponentPropsType>;defaultProps: ComponentPropsType;
};// 全部組件配置列表
const componentConfList: ComponentConfType[] = [QuestionInputConf,QuestionTitleConf,
];// 根據組件類型獲取組件
export function getComponentConfByType(type: string) {return componentConfList.find((c) => c.type === type);
}

2.3 重構useLoadQuestionData

代碼如下所示:

import { useParams } from "react-router-dom";
import { useRequest } from "ahooks";
import { getQuestionApi } from "@/api/question";
import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { resetComponents } from "@/store/componentsReducer";/*** 獲取帶加載狀態的問卷信息* @returns loading狀態,問卷信息*/
function useLoadQuestionData() {const { id = "" } = useParams();const dispatch = useDispatch();// ajax 加載const { data, loading, error, run } = useRequest(async (id: string) => {if (!id) {throw new Error("沒有問卷 id");}const data = await getQuestionApi(id);return data;},{manual: true,},);// 根據獲取的data,設置storeuseEffect(() => {if (!data) {return;}const { componentList = [] } = data;// componentList 存入redux storedispatch(resetComponents({ componentList }));// eslint-disable-next-line react-hooks/exhaustive-deps}, [data]);// 根據id變化,加載問卷數據useEffect(() => {run(id);// eslint-disable-next-line react-hooks/exhaustive-deps}, [id]);return { loading, error };
}export default useLoadQuestionData;

3 在畫布顯示問卷列表,點擊可選中

3.1 Redux獲取組件列表

自定義hook-useGetComponentInfo.ts 代碼如下所示:

import { StateType } from "@/store";
import { useSelector } from "react-redux";
import { ComponentsStateType } from "@/store/componentsReducer";function useGetComponentInfo() {const components = useSelector<StateType>((state) => state.components,) as ComponentsStateType;const { componentList = [] } = components;return { componentList };
}export default useGetComponentInfo;

3.2 根據Redux組件列表渲染組件

EditCanvas.tsx代碼如下所示:

import { FC } from "react";
import styles from "./EditCanvas.module.scss";import { Spin } from "antd";// import QuestionTitle from "@/components/QuestionComponents/QuestionTitle/Component";
// import QuestionInput from "@/components/QuestionComponents/QuestionInput/Component";
import useGetComponentInfo from "@/hooks/useGetComponentInfo";
import { getComponentConfByType } from "@/components/QuestionComponents";
import { ComponentInfoType } from "@/store/componentsReducer";type PropsType = {loading: boolean;
};function genComponent(componentInfo: ComponentInfoType) {const { type, props } = componentInfo;const componentConf = getComponentConfByType(type);if (componentConf == null) {return null;}const { Component } = componentConf;return <Component {...props} />;
}const EditCanvas: FC<PropsType> = ({ loading }) => {const { componentList = [] } = useGetComponentInfo();if (loading) {return (<div style={{ textAlign: "center", marginTop: "24px" }}><Spin /></div>);}return (<div className={styles.canvas}>{componentList.map((c) => {const { fe_id } = c;return (<div key={fe_id} className={styles["component-wrapper"]}><div className={styles.component}>{genComponent(c)}</div></div>);})}{/* <div className={styles["component-wrapper"]}><div className={styles.component}><QuestionTitle /></div></div><div className={styles["component-wrapper"]}><div className={styles.component}><QuestionInput /></div></div> */}</div>);
};export default EditCanvas;

3.3 點擊選擇組件,共享selectedId

componentsReducer/index.ts 添加selectId及修改,代碼如下:

import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { produce } from "immer";
import { ComponentPropsType } from "@/components/QuestionComponents";export type ComponentInfoType = {fe_id: string;type: string;title: string;props: ComponentPropsType;
};export type ComponentsStateType = {selectedId: string;componentList: Array<ComponentInfoType>;
};const INIT_STATE: ComponentsStateType = {selectedId: "",componentList: [],// 其他擴展
};export const componentsSlice = createSlice({name: "components",initialState: INIT_STATE,reducers: {// 重置所有組件resetComponents(state: ComponentsStateType,action: PayloadAction<ComponentsStateType>,) {return action.payload;},// 切換選中組件changeSelectedId: produce((draft: ComponentsStateType, action: PayloadAction<string>) => {draft.selectedId = action.payload;}),},
});export const { resetComponents, changeSelectedId } = componentsSlice.actions;
export default componentsSlice.reducer;

新增選中 css 樣式,EditCanvas.module 新增代碼如下所示:

.selected {border-color: #1890ff !important;
}

組件點擊選擇,點擊畫布空白處取消,阻止默認冒泡行為,EditCanvas.tsx代碼如下:

import { FC } from "react";
import styles from "./EditCanvas.module.scss";import { Spin } from "antd";// import QuestionTitle from "@/components/QuestionComponents/QuestionTitle/Component";
// import QuestionInput from "@/components/QuestionComponents/QuestionInput/Component";
import useGetComponentInfo from "@/hooks/useGetComponentInfo";
import { getComponentConfByType } from "@/components/QuestionComponents";
import { ComponentInfoType } from "@/store/componentsReducer";
import { useDispatch } from "react-redux";
import classNames from "classnames";
import { changeSelectedId } from "@/store/componentsReducer";type PropsType = {loading: boolean;
};function genComponent(componentInfo: ComponentInfoType) {const { type, props } = componentInfo;const componentConf = getComponentConfByType(type);if (componentConf == null) {return null;}const { Component } = componentConf;return <Component {...props} />;
}const EditCanvas: FC<PropsType> = ({ loading }) => {const { componentList = [], selectedId } = useGetComponentInfo();const dispatch = useDispatch();// 獲取當前選中的組件function handleClick(e: React.MouseEvent<HTMLDivElement>, fe_id: string) {e.stopPropagation();dispatch(changeSelectedId(fe_id));}if (loading) {return (<div style={{ textAlign: "center", marginTop: "24px" }}><Spin /></div>);}return (<div className={styles.canvas}>{componentList.map((c) => {const { fe_id } = c;// 拼接 class nameconst wrapperDefaultClassName = styles["component-wrapper"];const selectedClassName = styles.selected;const wrapperClassName = classNames({[wrapperDefaultClassName]: true,[selectedClassName]: fe_id === selectedId,});return (<div key={fe_id} className={wrapperClassName} onClick={(e) => handleClick(e, fe_id)}><div className={styles.component}>{genComponent(c)}</div></div>);})}{/* <div className={styles["component-wrapper"]}><div className={styles.component}><QuestionTitle /></div></div><div className={styles["component-wrapper"]}><div className={styles.component}><QuestionInput /></div></div> */}</div>);
};export default EditCanvas;

默認selectId為組件列表第一個,沒有不選中,useLoadQuestionData.ts代碼如下所示:

import { useParams } from "react-router-dom";
import { useRequest } from "ahooks";
import { getQuestionApi } from "@/api/question";
import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { resetComponents } from "@/store/componentsReducer";/*** 獲取帶加載狀態的問卷信息* @returns loading狀態,問卷信息*/
function useLoadQuestionData() {const { id = "" } = useParams();const dispatch = useDispatch();// ajax 加載const { data, loading, error, run } = useRequest(async (id: string) => {if (!id) {throw new Error("沒有問卷 id");}const data = await getQuestionApi(id);return data;},{manual: true,},);// 根據獲取的data,設置storeuseEffect(() => {if (!data) {return;}const { componentList = [] } = data;// 獲取默認的 selectedIdlet selectedId = "";if (componentList.length > 0) {selectedId = componentList[0].fe_id;}// componentList 存入redux storedispatch(resetComponents({ componentList, selectedId }));// eslint-disable-next-line react-hooks/exhaustive-deps}, [data]);// 根據id變化,加載問卷數據useEffect(() => {run(id);// eslint-disable-next-line react-hooks/exhaustive-deps}, [id]);return { loading, error };
}export default useLoadQuestionData;

效果如下圖所示:

在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述

關于

?QQ:806797785

??倉庫地址:https://gitee.com/gaogzhen

??倉庫地址:https://github.com/gaogzhen

[1]react官網[CP/OL].

[2]Redux官網[CP/OL].

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/93591.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/93591.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/93591.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

設置計劃任務自動備份mysql

windows系統下1.創建mysql自動備份腳本mysqlback.bat需將此腳本存放在mysql的bin文件夾下。確保此腳本執行成功了在進行第2步做計劃任務。echo off REM 定義備份目錄backup_dir、備份的文件名filename set "backup_dirD:\mysqlback" set "filenamemysqlback_%da…

飛機起落架輪軸深孔中間段電解擴孔內輪廓檢測 - 激光頻率梳 3D 輪廓檢測

摘要&#xff1a;飛機起落架輪軸深孔中間段電解擴孔內輪廓檢測存在精度要求高、結構復雜等挑戰。本文針對電解擴孔特殊工藝特征&#xff0c;探討激光頻率梳 3D 輪廓檢測技術的應用&#xff0c;分析其檢測原理、技術優勢及在輪軸深孔檢測中的實踐&#xff0c;為電解擴孔內輪廓高…

【軟考中級網絡工程師】知識點之入侵防御系統:筑牢網絡安全防線

目錄一、入侵防御系統基礎概念1.1 定義與作用1.2 與其他安全設備的關系二、入侵防御系統工作原理剖析2.1 數據包捕獲與預處理2.2 深度包檢測&#xff08;DPI&#xff09;技術2.3 威脅特征匹配2.4 行為分析與機器學習輔助檢測2.5 威脅處理與響應機制三、入侵防御系統功能全面解析…

Python爬蟲實戰:研究scrapfly-scrapers庫,構建電商/新聞/社交媒體數據采集系統

1. 引言 1.1 研究背景與意義 在大數據與人工智能技術深度滲透各行業的背景下,數據已成為企業決策、學術研究、產品創新的核心驅動力。互聯網作為全球最大的信息載體,蘊含海量結構化與非結構化數據(如電商商品信息、新聞資訊、社交媒體動態等),其價值挖掘依賴高效的數據采…

Python爬蟲反爬檢測失效問題的代理池輪換與請求頭偽裝實戰方案

Python爬蟲反爬檢測失效問題的代理池輪換與請求頭偽裝實戰方案 &#x1f31f; Hello&#xff0c;我是摘星&#xff01; &#x1f308; 在彩虹般絢爛的技術棧中&#xff0c;我是那個永不停歇的色彩收集者。 &#x1f98b; 每一個優化都是我培育的花朵&#xff0c;每一個特性都是…

【原理】C#構造函數可以標記為Static嗎

【從UnityURP開始探索游戲渲染】專欄-直達 實例構造函數&#xff08;Instance Constructor&#xff09;不能標記為static但C#提供了一種特殊的? 靜態構造函數&#xff08;Static Constructor&#xff09;專門用于初始化靜態成員。下面依次介紹他們&#xff1a; 1. ?實例構造…

數據結構--樹(3)

數據結構基礎&#xff08;13&#xff09; 文章目錄數據結構基礎&#xff08;13&#xff09;--樹樹的存儲結構樹的存儲方式1&#xff1a;雙親表示法&#xff08;順序存儲&#xff09;樹的存儲方式2&#xff1a;孩子表示法樹的存儲方式3&#xff1a;孩子兄弟表示法樹轉二叉樹森林…

sys.stdin讀取鍵盤輸入【持續更新~】

背景sys.stdin主要用來讀取鍵盤的一行或者多行輸入&#xff0c;讀取后表達形式為字符串。下文主要探討sys.stdin.readline()的使用&#xff0c;sys.stdin.read()參考&#xff1a;sys.stdin.readline()是逐行讀取&#xff0c;通常會配合.strip()清除首尾的換行符/空格sys.stdin.…

近閾值技術引領者:STM32U3系列的能效與安全革新

引言 當電池供電設備已深度融入生活的每一個角落&#xff0c;功耗控制與續航能力儼然成為制約技術演進的核心瓶頸。在此背景下&#xff0c;超低功耗新系列STM32U3憑借前沿的近閾值設計理念&#xff0c;為受功耗瓶頸限制的設備提供了突破性解決方案&#xff0c;也為能耗管理開啟…

Vue3 中的 provide 和 inject 詳解:實現跨組件通信

一、provide 和 inject 概述在 Vue3 中&#xff0c;provide 和 inject 是一對用于實現跨層級組件通信的 API&#xff0c;它們解決了 props 需要逐層傳遞的繁瑣問題。1.1 基本概念provide (提供)&#xff1a;在祖先組件中提供數據inject (注入)&#xff1a;在任意后代組件中注入…

Kafka 零拷貝(Zero-Copy)技術詳解

文章目錄1. 什么是零拷貝2. Kafka 如何實現零拷貝2.1 sendfile 系統調用2.2 mmap 內存映射3. 傳統拷貝 vs 零拷貝3.1 傳統文件傳輸流程3.2 零拷貝文件傳輸流程4. Kafka 零拷貝的具體實現4.1 消息消費時的零拷貝4.2 日志段文件的零拷貝5. 零拷貝帶來的性能優勢6. 零拷貝的適用場…

Vue 中 v-for 的使用及 Vue2 與 Vue3 的區別

v-for 基本用法v-for 是 Vue 中用于循環渲染列表的指令&#xff0c;基本語法如下&#xff1a;運行<!-- Vue2 和 Vue3 通用基本語法 --> <div v-for"(item, index) in items" :key"item.id">{{ index }} - {{ item.name }} </div>Vue2 和…

本地搭建dify+deepseek智能體

今天開始搭建智能體&#xff0c;學習一下&#xff0c;也是公司轉型所需。(Windows下的docker安裝給我差點干破防了&#xff0c;安裝了一周docker才成功。我真就要放棄的時候&#xff0c;又意外成功了/(ㄒoㄒ)/~~)0、準備階段 配置Windows10的基本配置。 按下鍵盤Windows鍵&…

網絡常識-SSE對比Websocket

SSE&#xff08;Server-Sent Events&#xff09;和Websocket都是用于實現服務器與客戶端實時通信的技術&#xff0c;但它們的設計理念、通信模式和適用場景有顯著區別。以下從核心差異和適用場景兩方面具體說明&#xff1a; 一、核心區別維度SSE&#xff08;Server-Sent Events…

lamp架構部署wordpress

CentOS 7主機&#xff1a;lamp.example.comIP&#xff1a;192.168.100.101、關閉防火墻與selinux# 關閉防火墻systemctl stop firewalldsystemctl disable firewalld# 關閉selinuxvim /etc/selinux/config # 或vim /etc/sysconfig/selinuxSELINUXdisabled:wq# 重啟reboot 2、開…

DC6v-36V轉3.2V1A恒流驅動芯片WT7017

DC6v-36V轉3.2V1A恒流驅動芯片WT7017WT7017是一款于連續工作模式下的降壓LED恒流轉換器&#xff0c;可驅動單只或多只LED,內置高精度電流檢測器&#xff0c;能通過外置電阻設定輸出電流,開關式1A恒流芯片。軟啟動、高達1MHZ開關頻率,開路保護,輸入范圍在6V-40VDC內都能穩定可靠…

js如何循環HTMLCollection

場景 當使用document.getElementsByClassName方法獲取一個包含DOM節點的集合arr時&#xff0c;正常的forEach和map操作都會報一個arr.map is not a function的錯誤因為這里的arr并不是標準的 數組 (Array)&#xff0c;而是一個 HTMLCollection 解決 使用document.querySelector…

Dart 逆襲之路:Flutter 4.0 如何推動移動端開發變革?

本文深入探討 Dart 語言在 Flutter 4.0 框架下如何推動移動端開發變革。開篇回顧 Dart 誕生背景與初期困境&#xff0c;闡述其在與 Flutter 結合后嶄露頭角。進而詳細剖析 Flutter 4.0&#xff0c;從全新渲染引擎帶來的性能飛躍、豐富實用新組件簡化開發&#xff0c;到手勢系統…

基于MATLAB的卷積神經網絡手寫數字識別

一、系統架構設計 #mermaid-svg-QQU8judlmQgHc2Lh {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QQU8judlmQgHc2Lh .error-icon{fill:#552222;}#mermaid-svg-QQU8judlmQgHc2Lh .error-text{fill:#552222;stroke:#5…

從廢棄到珍寶——舊物二手回收小程序系統的價值發現之旅

在我們的生活中&#xff0c;總有一些舊物因為各種原因而被遺棄在角落&#xff0c;它們或許不再新潮&#xff0c;或許不再實用&#xff0c;但它們卻承載著我們的記憶和情感。舊物二手回收小程序系統的出現&#xff0c;讓這些被遺忘的舊物重新煥發了生機&#xff0c;開啟了一段從…