React + 项目(从基础到实战) -- 第11期

目标

问卷编辑器的开发

设计UI - 拆分布局

水平垂直居中

在这里插入图片描述

画布 y方向滚动

在这里插入图片描述

自定义问卷组件

在这里插入图片描述

后端 返回组件数据

 //获取单个问卷信息{url: '/api/question/:id',method: 'get',response: () => {return {errno: 0,data: {id: Random.id(),title: Random.ctitle(),componentList:[//Title{id:Random.id(),type:'questionTitle', //组件类型不能重复,前后端统一title:"标题",props:{text:"问卷标题",level:1,isCenter:false}},//Input{id:Random.id(),type:'questionInput',title:"输入框",props:{title:"输入框",placeholder:"请输入内容",}},//Input2{id:Random.id(),type:'questionInput',title:"输入框2",props:{title:"输入框2",placeholder:"请输入内容2",}}]}}}},

前端 redux 存储后端返回组件数据

切片

import { createSlice , PayloadAction } from "@reduxjs/toolkit";import { ComponentPropsType } from "../../components/QuestionComponents";//单个组件的信息export type ComponentInfoType={fe_id : string,//为什么下划线type : string,title: string,props:ComponentPropsType}//redux存放组件列表//1. 定义数据结构export type ComponentsStateType={componentList:Array<ComponentInfoType>,}//2. 初始化const INIT_STATE:ComponentsStateType={componentList:[],//其他扩展}export const componentsSlice = createSlice({name:"components",initialState:INIT_STATE,reducers:{//重置所有组件//看不懂啊老铁!!!!resetComponentList:(state: ComponentsStateType , action: PayloadAction<ComponentsStateType>)=>{return action.payload}}})//导出所有的actionsexport const {resetComponentList} = componentsSlice.actionsexport default componentsSlice.reducer

store

import { configureStore } from '@reduxjs/toolkit'import userReducer, { UserStateType } from './userReducer'import componentsReducer , {ComponentsStateType}from './componentsReducer'export type StateType={user : UserStateType,components : ComponentsStateType}export default configureStore({reducer: {//分模块注册user: userReducer, // 存储user数据components : componentsReducer// 存储问卷组件列表的数据// 存储问卷组件列表的数据// 存储问卷信息数据}})

发请求时存储数据

import { useEffect , useState } from "react";import { useParams } from "react-router-dom";import { useRequest } from "ahooks";import {useDispatch} from 'react-redux'import {resetComponentList} from '../store/componentsReducer'//导入发起请求的函数import { getQuestinService } from "../services/question";function useLoadQuestionData() {const dispatch = useDispatch()const {id = ''} =useParams()const {data , loading , error , run} = useRequest(async (id : string) => {if(!id) throw new Error('不存在问卷id')const data = await getQuestinService(id)return data},{manual: true,})//根据获取的data 设置redux storeuseEffect(() => {if(!data) returnconst {title ='' , componentList = []} = data//获取到的componentList 存储到 Redux store中dispatch(resetComponentList({componentList}))},[data])//问卷改变时, 重新加载问卷数据useEffect(() => {run(id)},[id])return {loading,error,}}export default useLoadQuestionData;

在这里插入图片描述

页面画布区域显示组件列表

自定义hook获取数据

import { useSelector } from "react-redux";import { StateType } from "../store";import { ComponentsStateType } from "../store/componentsReducer";function useGetComponentInfo() {//使用useSelector获取store中的数据const componens= useSelector<StateType>(state => state.components) as ComponentsStateType//结构出空数组const {componentList = []} = componensreturn {componentList}}export default useGetComponentInfo;

重构canvas页面

import { FC } from 'react';import styles from './EditCanvas.module.scss';//静态展示import useGetComponentInfo from '../../../hooks/useGetComponentInfo';import { ComponentInfoType } from '../../../store/componentsReducer';import { getComponentConfByType } from '../../../components/QuestionComponents';type PropsType={loading : boolean}const EditCanvas: FC<PropsType> = ({loading}) => {const {componentList } = useGetComponentInfo();if(loading){return <div>loading</div>}//根据传入的组件 ,function getComponent(componetInfo : ComponentInfoType){const {type , props} = componetInfo//根据组件类型找到对应的组件配置const componentConf= getComponentConfByType(type)if(!componentConf) return nullconst {Component} = componentConfreturn <Component {...props} />}return (<div className={styles.canvas}>{componentList.map(c => {const {id} = creturn (<div key={id} className={styles['component-warpper']}><div className={styles.component}>{getComponent(c)}</div></div>)})}</div>);};export default EditCanvas;

点击组件选中效果

添加selectedId,点击时,修改当前选中组件id

import { createSlice , PayloadAction } from "@reduxjs/toolkit";import { ComponentPropsType } from "../../components/QuestionComponents";import {produce} from "immer";//单个组件的信息export type ComponentInfoType={// fe_id : string,//为什么是fe_idid: stringtype : string,title: string,props:ComponentPropsType}//redux存放组件列表//1. 定义数据结构export type ComponentsStateType={componentList:Array<ComponentInfoType>,selectedId:string}//2. 初始化const INIT_STATE:ComponentsStateType={selectedId:'',componentList:[],//其他扩展}export const componentsSlice = createSlice({name:"components",initialState:INIT_STATE,reducers:{//1. 重置所有组件//看不懂啊老铁!!!!resetComponentList:(state: ComponentsStateType , action: PayloadAction<ComponentsStateType>)=>{return action.payload},//2.修改选中的组件id//使用immer , 改进state不可变数据的写法changeSelctedId:produce((state: ComponentsStateType , action: PayloadAction<string>)=>{state.selectedId=action.payload})}})//导出所有的actionsexport const {resetComponentList} = componentsSlice.actionsexport default componentsSlice.reducer

页面注册点击事件

 //点击选中组件function handleClick(id: string) {dispatch(changeSelctedId(id))}

点击后改变样式

classsNames css样式的拼接

import classNames from 'classnames'; // 这个是实现css样式的拼接{componentList.map(c => {const {id} = c//拼接classnameconst defaultClassName=styles['component-warpper']const selectedClassName=styles.selectedconst wrapperClassName = classNames({[defaultClassName]: true,[selectedClassName]: id === selectedId})return (<div onClick={()=>{handleClick(id)}} key={id} className={wrapperClassName}><div className={styles.component}>{getComponent(c)}</div></div>)})}

在这里插入图片描述

点击空白处,取消选中效果

注意这里阻止冒泡的操作

在这里插入图片描述

默认初始加载时选择第一个组件

在这里插入图片描述

组件库

组件分组

left 布局搭建
选取 组件库中的 tabs组件
又提取出组件 componentlib

在这里插入图片描述

显示到组件库

在这里插入图片描述

点击,添加组件到画布

画布信息需要更新
画布信息存在Redux中

处理redux

在这里插入图片描述

页面中使用

在这里插入图片描述

组件属性面板

组件属性的配置

每个组件的属性不一样,单独配置

import React, {FC, useEffect} from "react";import { QuestionInputPropsType } from "./interface";//引入组件库import {Form ,Input} from "antd";const PropComponent:FC<QuestionInputPropsType> = (props:QuestionInputPropsType) => {const {title , placeholder} = props;return (<div><Formlayout="vertical"initialValues={{ title ,placeholder }}><Form.Item label="标题" name="title" rules={[{ required: true, message: '请输入标题' }]}><Input /></Form.Item><Form.Item label="Placeholder" name="placeholder"><Input/></Form.Item></Form></div>)}export default PropComponent;

画布中点击不同的组件时,监听变化,即时显示在右侧属性栏

在这里插入图片描述

组件配置中引入属性配置

在这里插入图片描述

属性面板显示组件属性

根据selectedID面板显示组件属性

在这里插入图片描述

在这里插入图片描述

onchange改变组件属性时,同步到Redux Store

改变组件属性时,统一交给上层的componentProops管理

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在redux store 中增加修改属性的方法

在这里插入图片描述

头部编辑栏

定义组件
页面中引入

import React , {FC} from "react";import styles from "./EditHeader.module.scss";import {Button,Space,Typography,}from 'antd';import { LeftOutlined } from "@ant-design/icons";import { useNavigate } from "react-router-dom";const {Title} = Typography;const EditHeader:FC = ()=>{const nav = useNavigate()return (<div className={styles['header-wrapper']}><div className={styles.header}><div className={styles.left}><Space><Button type="link" icon={<LeftOutlined></LeftOutlined>} onClick={()=>nav(-1)}>返回</Button><Title>问卷标题</Title></Space></div><div className={styles.main}></div><div className={styles.right}><Space><Button>保存</Button><Button>发布</Button></Space></div></div></div>)}export default EditHeader;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/9601.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蒸汽工厂的新翼:数字孪生锅炉引领未来

在飞速发展的工业4.0时代&#xff0c;数字孪生技术已经深入到我们生产生活的方方面面。而对于那些承载着重工业血脉的蒸汽工厂来说&#xff0c;一项新的技术正在悄然改变它们的未来。 走进蒸汽工厂&#xff0c;感受传统与现代的交融 蒸汽工厂&#xff0c;这个充满力量与热情的…

马化腾用了一年多的时间,告诉所有人,视频号小店是新风口!

大家好&#xff0c;我是电商笨笨熊 当腾讯说出自己要做电商的时候&#xff0c;所有人都在说&#xff0c;根本不可能&#xff1b; 甚至在视频号小店正式推出之后&#xff0c;依旧有人说&#xff0c;腾讯做电商就是笑话&#xff1b; 一个“抄”过来的项目&#xff0c;毫无特色…

Kubernetes容器技术详解

kubernetes Kubernetes&#xff08;K8s&#xff09;由Google打造&#xff0c;是一款功能强大、灵活可扩展的容器编排平台&#xff0c;引领云原生技术潮流。 Kubernetes主要解决以下4大点&#xff1a; 1.自动化运维平台 如下图所示&#xff1a; Kubernetes携手Docker&#xf…

探秘未来科技:数字化无人巡检的奇妙之旅

嘿&#xff0c;朋友们&#xff01;下午茶时间到&#xff01;趁着这会儿咱们来聊一个超级炫酷的话题——数字化无人巡检。想象一下&#xff0c;那些曾经需要人工跋山涉水、风吹日晒的巡检工作&#xff0c;现在正被一群“智能小分队”悄悄接手&#xff0c;是不是觉得既神奇又方便…

25岁软件工程师:19岁创业,25岁创建自己的工作室,谈一下我对创业的一点思考。

文章目录 &#x1f95d;About Me&#x1f3c0;关于工作室✅我对创业思考 大家好哈&#xff0c;欢迎查看工程师令狐本期节目。这篇文章主要是一篇回忆复盘总结文&#xff0c;复盘总结刚上大学到走向工作这段经历&#xff0c;自己的感悟、感想与收获&#xff0c;期望对读者有所帮…

安防监控/视频汇聚系统EasyCVR+AI智能分析助力解决校园霸凌事件

一、方案背景 校园霸凌这一校园中不应存在的现象&#xff0c;却屡见不鲜&#xff0c;它像一把锋利的刀&#xff0c;深深地刺入那些无辜的心灵&#xff0c;让受害者承受着无尽的痛苦。随着科技的进步与发展&#xff0c;我们应该追求有效、进步的手段来阻止校园霸凌事件的发生&a…

解决 Git拉取代码和本地代码丢失问题

git拉取代码&#xff0c;本地写的代码全部为空了&#xff0c;当时都蒙了&#xff0c;最后解决办法是找到对应文件的历史记录 举例&#xff1a;以本地的demo举例&#xff0c;不管是否有git或svn控制&#xff0c;都可以找到历史记录 解决办法&#xff1a; 1、对代码丢失的文件 …

【算法】Dijkstra求最短路算法

TOP提示&#xff1a;Dijkstra算法只适用于不含负权边的情况 Dijkstra算法是一个基于贪心&#xff0c;广搜和动态规划 求图中某点到其他所有点的最短路径的算法 一、步骤 首先我们先总结Dijkstra算法的完整步骤 我们需要一个dis数组存储从起点到达其他节点的最短距离&…

CSS学习笔记之中级教程(一)

1、CSS 布局 - display 属性 1.1 display 属性 display 属性是用于控制布局的最重要的 CSS 属性。 display 属性规定是否/如何显示元素。 每个 HTML 元素都有一个默认的 display 值&#xff0c;具体取决于它的元素类型。大多数元素的默认 display 值为 block 或 inline。 …

每日OJ题_记忆化搜索②_力扣62. 不同路径(三种解法)

目录 力扣62. 不同路径 解析代码1_暴搜递归&#xff08;超时&#xff09; 解析代码2_记忆化搜索 解析代码3_动态规划 力扣62. 不同路径 62. 不同路径 难度 中等 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器…

【MySQL数据库】详解数据库审核工具SQLE的部署及接口调用

SQLE部署及使用 1. 部署SQLE SQLE相信大家都不陌生吧&#xff0c;它是一款开源&#xff0c;支持多场景审核&#xff0c;支持标准化上线流程&#xff0c;原生支持 MySQL 审核且数据库类型可扩展的 SQL审核工具。我们可以基于此工具进行数据库SQL审核&#xff0c;提升SQL脚本质量…

视频怎么打水印?6个软件教你快速进行视频水印制作

视频怎么打水印&#xff1f;6个软件教你快速进行视频水印制作 添加水印是保护视频版权、提升视频专业性的重要手段之一。以下是六款软件&#xff0c;它们能够帮助你快速进行视频水印制作&#xff0c;让你的视频更具个性和专业性&#xff1a; 1.迅捷视频剪辑软件&#xff1a;…

5月白银现货最新行情走势

美联储5月的议息会议举行在即&#xff0c;但从联邦公开市场委员会&#xff08;FOMC&#xff09;近期透露的信息来看&#xff0c;降息似乎并没有迫切性。——美联储理事鲍曼认为通胀存在"上行风险"&#xff0c;明尼阿波利斯联邦储备银行行长卡什卡利提出了今年不降息的…

图片过大怎么处理变小?在线编辑图片工具推荐

在各种平台进行图片上传时&#xff0c;经常会遇到由于图片过大而无法成功上传的问题&#xff0c;为了顺利进行下一步操作&#xff0c;我们需要将图片进行缩小处理&#xff0c;通常情况下&#xff0c;我们可以使用各种软件工具来对图片进行缩小&#xff0c;如何快速有效地调整图…

前端面试题 | 常考题整理

本文为面试中出现的高频次考题&#xff0c;具体还是要看所有题。 目录 css 1、☆介绍下 BFC 及其应用 3、☆浮动清除 17、☆说几个未知宽高元素水平垂直居中方法 js 9、☆箭头函数与普通函数的区别是什么&#xff1f;构造函数可以使用 new 生成实例&#xff0c;那么箭头…

基于Springboot+Vue的Java项目-电影院购票系统开发实战(附演示视频+源码+LW)

大家好&#xff01;我是程序员衣一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

Screeps工程化之数量控制模块

前言 将Screeps的代码进行模块化后&#xff0c;可以将各个功能进行分离&#xff0c;互相不影响&#xff0c;本文将会介绍Screeps中如何进行creep的数量控制来维持房间资源的平衡和发展。本文仅为作者本人的游戏思路&#xff0c;并不是最佳实践&#xff0c;如有更好的实现方法可…

【概率论基础】 一篇文章缕清概率论常见概念关系

碎碎念&#xff1a;再写CSDN之前有一小段时间写数模公众号的经历&#xff0c;但是公众号看的人实在太少了&#xff0c;而且排版和公式、代码编辑都没有CSDN这么方便&#xff0c;所以坚持一算时间就没有更新了。公众号大多写的是概念性的基础&#xff0c;稍加修改搬到咱们的主战…

‘pip‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

因为python13不支持 pip install cx_Oracle&#xff0c;卸载了python13&#xff0c;重新安装python10&#xff0c;导致cmd命令不识别 pip &#xff0c;和python10&#xff0c;(;༎ຶД༎ຶ) 记录一种临时方案 如果你的命令行界面&#xff08;cmd&#xff09;不识别pip命令&am…

如何挑选“好用”的工业APP

我们日常生活中每天都在使用各种生活类的APP,然而&#xff0c;当我们谈到工业APP时&#xff0c;很多人可能并不那么熟悉。工业APP&#xff0c;虽然不像生活类APP那样直接面向广大消费者&#xff0c;但在工业领域却扮演着至关重要的角色。 先简单认识下啥是工业APP? 工业APP是…