'text:测试react-dnd'
This commit is contained in:
parent
0415665bc5
commit
62fae1dffe
|
|
@ -0,0 +1,14 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<link rel="stylesheet" href="//at.alicdn.com/t/font_2570680_2fgczr3435f.css">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"name": "example",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"start": "vite",
|
||||||
|
"lint:less": "stylelint **/*.{css,sass,less} --fix --allow-empty-input",
|
||||||
|
"build": "vite build --mode=production",
|
||||||
|
"build:stag": "vite build --mode=staging",
|
||||||
|
"serve": "vite preview",
|
||||||
|
"releash": "sh releash.sh",
|
||||||
|
"log": "standard-changelog -f && git add CHANGELOG.md"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@jest/types": "28.0.2",
|
||||||
|
"@testing-library/dom": "7.21.4",
|
||||||
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
|
"@testing-library/react": "12.1.5",
|
||||||
|
"@testing-library/user-event": "12.8.3",
|
||||||
|
"@types/node": "^16.18.3",
|
||||||
|
"@types/react-dom": "^16.9.19",
|
||||||
|
"js-cookie": "^2.2.1",
|
||||||
|
"jszip": "^3.4.0",
|
||||||
|
"less": "^3.9.0",
|
||||||
|
"less-loader": "^5.0.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"qs": "^6.11.0",
|
||||||
|
"react": "^16.14.0",
|
||||||
|
"react-beautiful-dnd": "^13.0.0",
|
||||||
|
"react-countup": "^4.3.3",
|
||||||
|
"react-custom-scrollbars": "^4.2.1",
|
||||||
|
"react-dnd": "^16.0.1",
|
||||||
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
|
"react-document-title": "^2.0.3",
|
||||||
|
"react-dom": "^16.14.0",
|
||||||
|
"react-draft-wysiwyg": "^1.14.5",
|
||||||
|
"react-loadable": "^5.5.0",
|
||||||
|
"react-redux": "^7.2.0",
|
||||||
|
"react-router-dom": "^5.1.2",
|
||||||
|
"react-scripts": "3.4.1",
|
||||||
|
"react-transition-group": "^4.4.1",
|
||||||
|
"redux": "^4.0.5",
|
||||||
|
"redux-thunk": "^2.3.0",
|
||||||
|
"typescript": "~4.2.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^16.14.43",
|
||||||
|
"@vitejs/plugin-react": "3.1.0",
|
||||||
|
"vite": "3.2.5",
|
||||||
|
"vite-plugin-svg-icons": "^1.0.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
.box{
|
||||||
|
height: 50px;
|
||||||
|
width: 50px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
import React, {Component, useState} from "react";
|
||||||
|
import "./App.css"
|
||||||
|
import CustDrag from "./component/CustDrag"
|
||||||
|
import CustDrop from "./component/CustDrop"
|
||||||
|
import {DndProvider} from "react-dnd";
|
||||||
|
import {HTML5Backend} from "react-dnd-html5-backend";
|
||||||
|
const dndList = [
|
||||||
|
{ label: "组件1", value: "组件1" },
|
||||||
|
{ label: "组件2", value: "组件2" },
|
||||||
|
{ label: "组件3", value: "组件3" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const DndPage = () => {
|
||||||
|
const [list, setList] = useState(dndList);
|
||||||
|
const dropChange = (res: any[]) => {
|
||||||
|
// const valList = (res || []).map((item) => item?.value);
|
||||||
|
// const filterList = dndList.filter((item) => !valList.includes(item.value));
|
||||||
|
// setList(filterList);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<DndProvider backend={HTML5Backend}>
|
||||||
|
<div >
|
||||||
|
<div>组件:</div>
|
||||||
|
<div>
|
||||||
|
<div style={{ border: "1px solid #000" }}>
|
||||||
|
{list.map((item,index) => {
|
||||||
|
return <span style={{margin:"0 10px"}} key={index}>
|
||||||
|
<CustDrag key={item.value} data={item} />
|
||||||
|
</span>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: "10px" }}>用例列表:</div>
|
||||||
|
<CustDrop onChange={dropChange} />
|
||||||
|
</div>
|
||||||
|
</DndProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
class App extends Component {
|
||||||
|
eventLogger = (e: MouseEvent, data: Object) => {
|
||||||
|
console.log('Event: ', e);
|
||||||
|
console.log('Data: ', data);
|
||||||
|
};
|
||||||
|
handleStart = ()=>{
|
||||||
|
console.log(1)
|
||||||
|
}
|
||||||
|
handleDrag = (e: MouseEvent)=>{
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
handleStop = (e: MouseEvent)=>{
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const dragHandlers = {onStart: this.handleStart, onStop: this.handleStop};
|
||||||
|
return (
|
||||||
|
<div className="box" style={{height: '500px', width: '500px', position: 'relative', overflow: 'auto', padding: '0'}}>
|
||||||
|
<DndPage />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { useDrag } from "react-dnd";
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const CustDrag = ({ data }) => {
|
||||||
|
const [{ opacity }, dragRef] = useDrag({
|
||||||
|
type: "Field",
|
||||||
|
item: { ...data },
|
||||||
|
collect: (monitor) => ({
|
||||||
|
opacity: monitor.isDragging() ? 0.5 : 1,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span ref={dragRef} style={{ opacity, cursor: "move" }}>
|
||||||
|
{data?.label}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default CustDrag
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
import { useDrop } from "react-dnd";
|
||||||
|
import React, {useRef, useState} from "react";
|
||||||
|
import CustDrag from "@/component/CustDrag";
|
||||||
|
// 同级为排序
|
||||||
|
// 跨级为插入
|
||||||
|
import DragSortItemComponent from "@/component/DragSortItemComponent"
|
||||||
|
const dndList = [
|
||||||
|
{id:1, label: "组件1", value: "组件1" },
|
||||||
|
{id:2,label: "组件2", value: "组件2" },
|
||||||
|
{id:3, label: "组件3", value: "组件3" },
|
||||||
|
];
|
||||||
|
// @ts-ignore
|
||||||
|
const CustDrop = ({ onChange }) => {
|
||||||
|
const [itemClass, setItemClass] = useState<{ key: number | null; value: string }>({
|
||||||
|
key: null,
|
||||||
|
value: '',
|
||||||
|
})
|
||||||
|
const sortItems = useRef<{ dragRow: any; placeRow: any; posi: string }>({
|
||||||
|
dragRow: {},
|
||||||
|
placeRow: {},
|
||||||
|
posi: '',
|
||||||
|
})
|
||||||
|
const [value, setValue] = useState<any[]>(dndList);
|
||||||
|
const [{ canDrop, isOver }, drop] = useDrop({
|
||||||
|
accept: 'Field',
|
||||||
|
drop: (item) => {
|
||||||
|
|
||||||
|
// const { dragRow, placeRow, posi } = sortItems.current
|
||||||
|
// let _map: any[] = JSON.parse(JSON.stringify(dndList))
|
||||||
|
// let index1 = _map.findIndex(v => v.id === dragRow.id) // 拖拽的itemIndex
|
||||||
|
// _map.splice(index1, 1) // 先删掉拖拽的,在获取放置的
|
||||||
|
const targetValue = [...value];
|
||||||
|
targetValue.push(item);
|
||||||
|
setValue(targetValue);
|
||||||
|
console.log(item,value)
|
||||||
|
onChange(targetValue);
|
||||||
|
// let index = _map.findIndex(v => v.id === placeRow.id) // 放置的itemIndex
|
||||||
|
// if (index !== -1 && index1 !== -1) {
|
||||||
|
// _map.splice(posi === 'bottom' ? index + 1 : index, 0, dragRow)
|
||||||
|
// setValue(() => _map)
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
collect: (monitor) => ({
|
||||||
|
// 是否放置在目标上
|
||||||
|
isOver: monitor.isOver(),
|
||||||
|
// 是否开始拖拽
|
||||||
|
canDrop: monitor.canDrop(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
// 展示拖动时的界面效果
|
||||||
|
const showCanDrop = () => {
|
||||||
|
if (canDrop && !isOver && !value.length) return <div>请拖拽到此处</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const delItem = (ind: number) => {
|
||||||
|
const newValue = [...value];
|
||||||
|
newValue.splice(ind, 1);
|
||||||
|
setValue(newValue);
|
||||||
|
onChange(newValue);
|
||||||
|
};
|
||||||
|
const onItemDragClass = (key:number,value:string) => {
|
||||||
|
console.log(key,value,itemClass.value)
|
||||||
|
if (itemClass.value !== value) {
|
||||||
|
setItemClass(() => {
|
||||||
|
let data = { key, value }
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onSortItemChange = (dragRow: any, placeRow: any, posi: string) => {
|
||||||
|
console.log(dragRow,placeRow,posi)
|
||||||
|
sortItems.current = { dragRow, placeRow, posi }
|
||||||
|
}
|
||||||
|
// 内容展示
|
||||||
|
const showValue = () => {
|
||||||
|
return value.map((item, index: number) => {
|
||||||
|
return (
|
||||||
|
<div key={index} >
|
||||||
|
<CustDrag data={item} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={drop}
|
||||||
|
style={{ border: '1px solid #000', marginTop: '10px', minHeight: '200px', background: '#fff' }}
|
||||||
|
>
|
||||||
|
{showCanDrop()}
|
||||||
|
{showValue()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default CustDrop
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
/**
|
||||||
|
* 通用拖拽排序的容器
|
||||||
|
* @param row 当前行
|
||||||
|
* @param onItemDragClass 拖拽过程的样式 top | bottom
|
||||||
|
* @param onSortItemChange 拖拽结束后返回的值 dragRow 当前拖拽 placeRow 放置的,posi 位置 top | bottom
|
||||||
|
* @param keyName 键名
|
||||||
|
*/
|
||||||
|
import {useDrag, useDrop, XYCoord} from "react-dnd";
|
||||||
|
import {useRef} from "react";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
row: any,
|
||||||
|
onItemDragClass: (key:number,value:string) => void,
|
||||||
|
onSortItemChange: (dragRow: any, placeRow: any, posi: string) => void // 排序后
|
||||||
|
keyName: string
|
||||||
|
}
|
||||||
|
const DragSortItemComponent:React.FC<IProps> = props => {
|
||||||
|
const { row,onItemDragClass,onSortItemChange,keyName } = props
|
||||||
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
|
/**
|
||||||
|
* 拖拽容器
|
||||||
|
*/
|
||||||
|
const [, drop] = useDrop({
|
||||||
|
// 定义拖拽的类型
|
||||||
|
accept: 'sort',
|
||||||
|
drop: (item, monitor) => {
|
||||||
|
const didDrop = monitor.didDrop()
|
||||||
|
if (didDrop) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
},
|
||||||
|
canDrop: (item, mointor) => {
|
||||||
|
// 阻止默认拖拽释放
|
||||||
|
onItemDragClass(row[keyName], '')
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
hover: (item: any, monitor) => {
|
||||||
|
const didHover = monitor.isOver({ shallow: true })
|
||||||
|
if (didHover) {
|
||||||
|
// 拖拽目标的id
|
||||||
|
const dragIndex = item[keyName]
|
||||||
|
// 放置目标id 可以用index | id 只要是number,数据里唯一的就可以
|
||||||
|
const hoverIndex = row[keyName]
|
||||||
|
// 如果一样不处理
|
||||||
|
if (dragIndex === hoverIndex) {
|
||||||
|
onItemDragClass(row[keyName], '')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 获取放置的位置
|
||||||
|
const hoverBoundingRect = ref.current?.getBoundingClientRect() as DOMRect
|
||||||
|
// 获取放置的Y轴中点
|
||||||
|
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
|
||||||
|
// 获取拖拽目标偏移量
|
||||||
|
const clientOffset = monitor.getClientOffset() as XYCoord
|
||||||
|
const hoverClientY = clientOffset.y - hoverBoundingRect.top
|
||||||
|
if (dragIndex !== hoverIndex) {
|
||||||
|
if (hoverMiddleY < hoverClientY) {
|
||||||
|
onItemDragClass(row[keyName], 'bottom')
|
||||||
|
} else {
|
||||||
|
onItemDragClass(row[keyName], 'top')
|
||||||
|
}
|
||||||
|
// 如果不做成通用拖拽容器,把参数存起来,把这个放在useDrag的end方法里,
|
||||||
|
onSortItemChange(item, row, hoverMiddleY < hoverClientY ? 'bottom' : 'top')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
collect: monitor => ({
|
||||||
|
isOver: monitor.isOver({ shallow: true }),
|
||||||
|
canDrop: monitor.canDrop(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* 定义拖拽
|
||||||
|
* isDragging 是否拖拽
|
||||||
|
*/
|
||||||
|
// const [{ isDragging }, drag] = useDrag({
|
||||||
|
// item: { ...row, type: 'sort'},
|
||||||
|
// end: () => {
|
||||||
|
// // onSortItemChange(item, row, hoverMiddleY < hoverClientY ? 'bottom' : 'top')
|
||||||
|
// },
|
||||||
|
// collect: monitor => ({
|
||||||
|
// isDragging: monitor.isDragging(),
|
||||||
|
// didDrop: monitor.isDragging(),
|
||||||
|
// }),
|
||||||
|
// })
|
||||||
|
// drop(drag(ref))
|
||||||
|
return (
|
||||||
|
<div ref={ref} >
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default DragSortItemComponent
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import App from './App';
|
||||||
|
import {DndProvider} from "react-dnd"
|
||||||
|
import {HTML5Backend} from "react-dnd-html5-backend"
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<App />
|
||||||
|
|
||||||
|
,document.getElementById('root'));
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"importHelpers": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"types": ["webpack-env", "vite/client", "vite-plugin-pages/client"],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/*"]
|
||||||
|
},
|
||||||
|
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"platform/**/*.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue",
|
||||||
|
"tests/**/*.ts",
|
||||||
|
"tests/**/*.tsx"
|
||||||
|
],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
import {ConfigEnv, UserConfigExport} from 'vite'
|
||||||
|
// @ts-ignore
|
||||||
|
import viteSvgIcons from "vite-plugin-svg-icons";
|
||||||
|
import React from '@vitejs/plugin-react'
|
||||||
|
// @ts-ignore
|
||||||
|
import qiankun from "vite-plugin-qiankun"
|
||||||
|
// @ts-ignore
|
||||||
|
import path, {resolve} from 'path'
|
||||||
|
|
||||||
|
const pathResolve = (dir: string): any => {
|
||||||
|
return resolve(__dirname, '.', dir)
|
||||||
|
}
|
||||||
|
console.log(__dirname);
|
||||||
|
|
||||||
|
const alias: Record<string, string> = {
|
||||||
|
'@': pathResolve('src'),
|
||||||
|
'api': pathResolve('src/api'),
|
||||||
|
'compoents': pathResolve('src/compoents'),
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default ({command}: ConfigEnv): UserConfigExport => {
|
||||||
|
const prodMock = true
|
||||||
|
return {
|
||||||
|
base: "/workbench",
|
||||||
|
css:{
|
||||||
|
devSourcemap:true
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
port: 3001,
|
||||||
|
host: '0.0.0.0',
|
||||||
|
open: true,
|
||||||
|
proxy: {
|
||||||
|
// 代理配置
|
||||||
|
'/api': {
|
||||||
|
target: 'http://192.168.31.150:8080/',
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: path => path.replace(/^\/api/, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
manualChunks: {
|
||||||
|
echarts: ['echarts']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
React(),
|
||||||
|
viteSvgIcons({
|
||||||
|
// 指定需要缓存的图标文件夹
|
||||||
|
iconDirs: [path.resolve(process.cwd(), 'src/assets/svg')],
|
||||||
|
// 指定symbolId格式
|
||||||
|
symbolId: 'icon-[dir]-[name]',
|
||||||
|
}),
|
||||||
|
qiankun("workbench", {
|
||||||
|
useDevMode: true
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,13 +7,13 @@ import { ElMessage } from "element-plus";
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
import {renderWithQiankun,qiankunWindow,QiankunProps} from "vite-plugin-qiankun/dist/helper"
|
import {renderWithQiankun,qiankunWindow,QiankunProps} from "vite-plugin-qiankun/dist/helper"
|
||||||
let instance = null
|
let instance:any = null
|
||||||
const render = (props:QiankunProps={})=>{
|
const render = (props:QiankunProps={})=>{
|
||||||
const {container} = props
|
const {container} = props
|
||||||
const appEle:string |Element = container?.querySelector("#app")||"#app"
|
const appEle:string |Element = container?.querySelector("#app")||"#app"
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
instance = app
|
instance = app
|
||||||
app.use(ElementPlus, { size: store.state.app.elementSize })
|
app.use(ElementPlus, { size: "small" })
|
||||||
app.use(store)
|
app.use(store)
|
||||||
app.config.globalProperties.$message = ElMessage
|
app.config.globalProperties.$message = ElMessage
|
||||||
// app.config.performance = true
|
// app.config.performance = true
|
||||||
|
|
@ -37,7 +37,7 @@ const initQianKun = ()=>{
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export async function mount(props){
|
export async function mount(props:any){
|
||||||
console.log('基座下发的能力:', props);
|
console.log('基座下发的能力:', props);
|
||||||
render(props)
|
render(props)
|
||||||
// return new Promise(((resolve, reject) => {
|
// return new Promise(((resolve, reject) => {
|
||||||
|
|
|
||||||
33592
pnpm-lock.yaml
33592
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue