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.hqwc.cn/news/670607.html

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

相关文章

测试用例执行的结果pass_fail_block_skip

pass fail block skip 测试用例的执行结果通常包括以下几个方面&#xff1a; 1. **测试结果状态**&#xff1a;通常分为“通过”、“失败”、“阻塞”和“跳过”等状态。 - **通过**&#xff1a;测试用例执行完毕&#xff0c;预期结果与实际结果一致。 - **失败**&am…

【AI】深度学习框架的期望与现实 机器学习编译尚未兑现其早期的一些承诺……

深度学习框架的期望与现实 机器学习编译尚未兑现其早期的一些承诺…… 来自&#xff1a;Axelera AI 资深软件工程师 Matthew Barrett 原帖是linkedin帖子&#xff1a; https://linkedin.com/posts/matthew-barrett-a49929177_i-think-its-fair-to-say-that-ml-compilation-ac…

Flask应用的部署和使用,以照片分割为例。

任务是本地上传一张照片&#xff0c;在服务器端处理后&#xff0c;下载到本地。 服务器端已经封装好了相关的程序通过以下语句调用 from amg_test import main from test import test main() test() 首先要在虚拟环境中安装flask pip install Flask 文件组织架构 your_pro…

Redis-单机安装

试图从官网注册不了我也不知道什么情况。 网盘自取吧&#xff0c;链接&#xff1a;https://pan.baidu.com/s/1KERBQaH9gCT10AGt9z0_jg?pwdyjen 安装比较简单&#xff0c;照着敲就完了每一步都试过了&#xff0c;先单机安装&#xff0c;后面搭建集群。 1.将安装包放到/usr/…

Nest 快速上手 —— (三)中间件 / 异常过滤器

一、 中间件&#xff08;Middleware&#xff09; 1.特点 中间件是一个在路由处理程序之前被调用的函数。中间件函数可以访问请求和响应对象&#xff0c;以及应用程序请求-响应周期中的next()中间件函数。下一个中间件函数通常由一个名为next的变量表示。 中间件函数可以执行以…

Xshell 7启动报错 产品运行所需的信息检索失败

错误信息 产品运行所需的信息检索失败 请重新安装Xshell Code:40002 解决办法 1、把压缩包解压出来 2、在“!)绿化处理.bat”上面右键以管理员身份运行

高项-案例分析万能答案(作业分享)

项目管理&#xff1a;每天进步一点点~ 活到老&#xff0c;学到老 ヾ(◍∇◍)&#xff89;&#xff9e; 何时学习都不晚&#xff0c;加油 一、通用问题原因: 1.项目经理管理经验不足&#xff0c;没有及时发现和解决xx方面的问题。 2.项目管理计划没有得到关键干系人的评审确…

PM - ICE 评分模型:快速的优先级排序框架

ICE 评分模型&#xff08;Impact, Confidence, Ease&#xff09;是一种项目管理和决策工具&#xff0c;广泛用于优先排序和决定应该优先实施哪些项目或任务。 它是由 Sean Ellis 提出的&#xff0c;主要用于增长黑客领域&#xff0c;帮助团队识别和优先处理能带来最大增长的机…

MaxKB宝塔Docker安装并配置域名访问

准备 Linux系统 bt面板 默认环境LNMP随便装 服务器环境配置最好是4G&#xff0c; 占用硬盘存储大概1G 对于一些海外AI产品的对接需要使用香港或者海外的服务器 安装 在宝塔面板中打开SSH或者你本地使用SSH工具去链接服务器 运行docker命令 前提是放开服务器的8080端口 doc…

javaweb学习week7

javaweb学习 十四.Springboot 1.配置优先级 Springboot中支持三种格式的配置文件&#xff1a; 注意&#xff1a;虽然Springboot支持多种格式配置文件&#xff0c;但是在项目开发时&#xff0c;推荐使用一种格式的配置&#xff08;yml是主流&#xff09; Springboot除了支持…

与Apollo共创生态:助力自动驾驶迈向新台阶

引言Apollo七周年大会企业协同工具链携手伙伴共创生态未来展望与总结 引言 2024年4月19日&#xff0c;一场智能汽车未来的盛宴正朝我们走来——Apollo开放平台的七周年大会。 此次大会主题为“破晓•拥抱智变时刻”其中“破晓”象征着新时代的曙光&#xff0c;意味着智能汽车技…

数据库原理与应用实验三 嵌套查询

实验目的和要求 加深和掌握对嵌套查询的理解和应用 实验环境 Windows10 SQLServer 实验内容与过程 图书&#xff08;书号&#xff0c;书名&#xff0c;价格&#xff0c;出版社&#xff09; 读者&#xff08;卡号&#xff0c;姓名&#xff0c;年龄&#xff0c;所属单位&a…