Javascript 滚动后,对Dnd的位置做出反应
我正在使用Javascript 滚动后,对Dnd的位置做出反应,javascript,reactjs,drag-and-drop,react-dnd,Javascript,Reactjs,Drag And Drop,React Dnd,我正在使用dnd使表行可拖动。 如果我从上到下拖动,拖动效果很好,当我向上滚动页面时,页面会脱离位置。 我不知道为什么。 而且,我没有发现css有什么奇怪的地方 我不知道为什么会发生这种情况,也不知道如何解决。 这是我的问题的一个例子 这是我的代码: import update from "immutability-helper"; import * as React from "react"; import { DragDropContext, Draggable, Droppable }
dnd
使表行可拖动。如果我从上到下拖动,拖动效果很好,当我向上滚动页面时,页面会脱离位置。
我不知道为什么。
而且,我没有发现css有什么奇怪的地方
我不知道为什么会发生这种情况,也不知道如何解决。 这是我的问题的一个例子 这是我的代码:
import update from "immutability-helper";
import * as React from "react";
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
import { WithNamespaces, withNamespaces } from "react-i18next";
import { toastr } from "react-redux-toastr";
import * as HttpHelper from "../../httpHelper";
import { FormState } from "../common/ValidatedForm";
type Props = WithNamespaces & {
id: number;
displayName: string;
type: string;
language: any;
};
interface Fields {
columns: any;
}
type State = FormState<Fields> & {
isLoading: boolean,
canSave: boolean,
isSaving: boolean,
possibleTags: any,
configTagModalActive: boolean,
previewModalActive: boolean,
activeTag: any
};
const getItemStyle = (isDragging: any, draggableStyle: any) => ({
...draggableStyle,
opacity: isDragging ? 1 : 1,
boxShadow: "0px 0px 0px 1px #8b8b8b",
});
const shadowColor = "#a0a0a057";
const Column = (props: any) => {
function findindex(val: any, pt: any) {
const list = pt ? props.possibleTags : props.tags;
return list.findIndex((item: any) => val == item.name);
}
function findindexofhelptext(val: any, pt: any) {
const list = pt;
return list.findIndex((item: any) => val == item.language);
}
return (
<tr ref={props.provided.innerRef} {...props.provided.draggableProps} style={getItemStyle(props.snapshot.isDragging, props.provided.draggableProps.style)} className={"draggablerow " + (props.snapshot.isDragging ? "draggedrow" : "") } key={props.indexnr} data-id={props.index} >
<td {...props.provided.dragHandleProps} style={{width: "50px", textAlign: "center", cursor: "move"}}><i className="fa fa-bars" style={{lineHeight: "40px", fontSize: "24px"}}></i></td>
<td style={{ textAlign: "center", width: "100px" }}>
<input
type="checkbox"
className="flipswitch"
id={props.index}
checked={props.export}
onChange={props.toggleVisible}
/>
</td>
<td style={{width: "350px" }}>
<input
type="text"
name="caption"
id={props.index}
className="form-control"
value={props.caption}
onChange={props.onTextUpdate}
style={{boxShadow: "2px 2px 3px 1px" + shadowColor}}
/>
</td>
<td style={{width: "350px" }}>
<input
type="text"
name="fieldname"
id={props.index}
className="form-control"
value={props.fieldname}
onChange={props.onTextUpdate}
style={{boxShadow: "2px 2px 3px 1px" + shadowColor}}
/>
</td>
<td style={{width: "400px"}}>
<div className="tags-input" style={tagInputStyle}>
{Object.keys(props.tags).map((key, i) =>
<div key={i} className="tag" onClick={props.onConfigButtonClicked} data-id={i} data-parent={props.index}>
{props.tags[i].name} <i className="fa fa-trash" id={props.index} data-key={i} data-name={props.tags[i].name} onClick={props.onDeleteTag} style={{float: "right"}} ></i>
</div>
)}
</div>
</td>
<td style={{ textAlign: "center", width: "100px" }}>
<button onClick={() => props.onDeleteColumn(props.index)} type="button" style={{padding : "8px 16px", boxShadow: "2px 2px 2px 1px" + shadowColor }} className="btn btn-danger btn-rounded"><i className="fa fa-trash"></i></button>
</td>
</tr>
);
};
const reorder = (list: any, startIndex: any, endIndex: any) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
interface SetColumnsResponse extends HttpHelper.ResponseData { columns: any; }
class CrmConnectorColumns extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.moveColumn = this.moveColumn.bind(this);
this.state = {
isLoading: true,
isSaving: false,
canSave: false,
errorColor: "danger",
fields: { columns: [] },
deleteModalActive: false,
configTagModalActive: false,
previewModalActive: false,
activeTag: {name: "", attributes: [{name: "", value: ""}]},
possibleTags: [
{name: "PRIMARY", status: "new", helptexts: [
{language: "nl", helptext: "Dit is de primary key"},
{language: "en", helptext: "This is the primary key"}
], attributes: [], uses: 1},
{name: "SUBTITLE", status: "new", helptexts: [
{language: "nl", helptext: "Dit is de subtitel van een record"},
{language: "en", helptext: "This is The subtitle of a record"}
], attributes: [], uses: 1},
{name: "URL", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als link."},
{language: "en", helptext: "The value becomes a link."}
], attributes: [
{name: "link", status: "new", helptexts: [
{language: "nl", helptext: "De link krijgt deze waarde. Voorbeeld waarde is \"http://www.google.nl?search=[naam]\". de waarde van \"[naam]\" wordt ingevuld."},
{language: "en", helptext: "The link gets this value. Example value is \"http://www.google.nl?search=[name]\". the value of \"[name]\" gets filled in."}
]}
], uses: undefined},
{name: "TITLE", status: "new", helptexts: [
{language: "nl", helptext: "Dit is de hoofdtitel van een record"},
{language: "en", helptext: "This is the maintitle of a record"}
], attributes: [], uses: 1},
{name: "PHONE", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als telefoonnummer"},
{language: "en", helptext: "The value becomes a phonenumber"}
], attributes: [], uses: undefined},
{name: "BUTTON", status: "new", helptexts: [
{language: "nl", helptext: "Uiterlijk van een knop"},
{language: "en", helptext: "The value becomes a button"}
], attributes: [], uses: undefined},
{name: "EMAIL", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als e-mail adres"},
{language: "en", helptext: "The value becomes a emailaddress"}
], attributes: [], uses: undefined},
{name: "IMAGE", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt als afbeelding weergegeven"},
{language: "en", helptext: "The value gets displayed as image"}
], attributes: [], uses: undefined},
{name: "HTML", status: "new", helptexts: [
{language: "nl", helptext: "De waarde wordt gezien als HTML"},
{language: "en", helptext: "The value gets seen as custom HTML"}
], attributes: [
{name: "HTML code", status: "new", helptexts: [
{language: "nl", helptext: "Vul hier je custom HTML code in. De waarde tussen de [] word vervangen door de data."},
{language: "en", helptext: "Enter your custom HTML here. The value between the [] will be replaced for the value."}
]}
], uses: undefined}
]
};
this.onDragEnd = this.onDragEnd.bind(this);
}
onDragEnd(result: any) {
// dropped outside the columns table
if (!result.destination) {
return;
}
let newlist = [...this.state.fields.columns];
newlist = reorder(
newlist,
result.source.index,
result.destination.index
);
Object.keys(newlist).forEach((nr) => {
newlist[parseInt(nr, 10)].index = parseInt(nr, 10);
});
this.setState({ fields: { columns: newlist } });
this.setState({ canSave: true });
}
async componentDidMount() {
console.log("Start select columns");
const fields = await HttpHelper.getJson<Fields>(`/${this.props.type}/${this.props.id}/columns`);
this.setState(prevState => {
return update(prevState, {
fields: { $set: fields },
isLoading: { $set: false },
});
});
if (this.state.fields.columns == undefined) {
this.setState({ fields: { columns: [] } });
}
for (let i = 0; i < fields.columns.length; i++) {
fields.columns[i].index = i;
}
this.setState({ fields: { columns: fields.columns } });
const newlist = [...this.state.possibleTags];
for (const column of fields.columns) {
for (const tags of column.tags) {
const index = newlist.map((item) => item.name).indexOf(tags.name);
if (newlist[index].uses > 0) {
newlist[index].uses = 0;
}
}
}
this.setState({ possibleTags: newlist });
}
moveColumn(index: any, indexnr: any) {
const cards = this.state.fields.columns;
const sourceCard = cards.find((card: any) => card.index === index);
const sortCards = cards.filter((card: any) => card.index !== index);
sortCards.splice(indexnr, 0, sourceCard);
Object.keys(sortCards).forEach((nr) => {
sortCards[nr].index = parseInt(nr, 10);
});
this.setState({ fields: { columns: sortCards } });
this.setState({ canSave: true });
}
onDragStart = (e: any) => {
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/html", e.target.parentNode);
e.dataTransfer.setDragImage(e.target.parentNode, 20, 20);
}
ondragOver(e: any) {
e.preventDefault();
}
public render() {
const columns = this.state.fields.columns || [] ;
const { t } = this.props;
let placeholder: any;
if (columns.length < 1) {
placeholder = <tr style={{boxShadow: "0px 0px 0px 1px #8b8b8b", textAlign: "center"}} className={"draggablerow"}><td colSpan={6} >{t("placeholder")}</td></tr>;
}
return (
<form>
<div className="App">
<main>
<button onClick={this.onSubmit} className="btn btn-primary" type="submit" style={{float: "right", boxShadow: "2px 2px 3px 1px" + shadowColor}} disabled={!this.state.canSave || this.state.isSaving}>{this.state.isSaving ? <i className="fa fa-spinner fa-spin"></i> : ""} {this.props.t("update")}</button>
<button onClick={this.onPreviewButtonClicked} type="button" className="btn btn-primary" style={{float: "right", boxShadow: "2px 2px 3px 1px" + shadowColor, marginRight: "5px"}} >Preview</button><br/><br/>
<DragDropContext onDragEnd={this.onDragEnd}>
<table className="col-8 table columns" style={{tableLayout: "auto"}} >
<thead className="" style={{border: "2px solid #1b2847", background: "#1b2847", color: "white"}}>
<tr>
<th colSpan={2} style={{textAlign: "center"}}>
<button onClick={this.onAddColumn} disabled={columns.length > 14 ? true : false} type="button" style={{padding : "8px 16px", boxShadow: "2px 2px 3px 1px" + shadowColor }} className="btn btn-primary btn-rounded"><i className="fa fa-plus"></i> </button>
</th>
<th>{t("displayname")}</th>
<th>Element</th>
<th>Tags</th>
<th></th>
</tr>
</thead>
<Droppable droppableId="droppable" direction="vertical">
{(provided: any) => (
<tbody ref={provided.innerRef}>
{Object.keys(columns).map((element, key) => (
<Draggable key={"draggable" + key} draggableId={element} index={key}>
{(provided, snapshot) => (
<Column
key={"column" + key}
indexnr={key}
toggleVisible={this.toggleVisible}
onTextUpdate={this.onTextUpdate}
onDeleteColumn={this.onDeleteColumn}
onDeleteTag={this.onDeleteTag}
onAddTag={this.onAddTag}
possibleTags={this.state.possibleTags}
onConfigButtonClicked={this.onConfigButtonClicked}
onPreviewButtonClicked={this.onPreviewButtonClicked}
onClosePreview={this.onClosePreview}
provided={provided}
snapshot={snapshot}
language={this.props.language}
{...columns[key]}
/>
)}
</Draggable>
))}
{provided.placeholder}
</tbody>
)}
</Droppable>
</table>
</DragDropContext>
</main>
</div>
</form>
);
}
}
export default withNamespaces(["crmConnectorColumns", "Common"])(CrmConnectorColumns);
从“不变性助手”导入更新;
从“React”导入*作为React;
从“dnd”导入{DragDropContext,Draggable,dropable};
从“react-i18next”导入{WithNamespaces,WithNamespaces};
从“react redux toastr”导入{toastr};
从“../../HttpHelper”导入*作为HttpHelper;
从“./common/ValidatedForm”导入{FormState};
键入Props=withnamespace&{
id:编号;
显示名称:字符串;
类型:字符串;
语言:任何语言;
};
接口字段{
列:任意;
}
类型State=FormState&{
isLoading:布尔值,
canSave:boolean,
isSaving:boolean,
可能的,可能的,
configTagModalActive:布尔值,
previewModalActive:布尔值,
activeTag:有吗
};
const getItemStyle=(IsDraging:any,DragableStyle:any)=>({
…拖拉风格,
不透明度:IsDraging?1:1,
boxShadow:“0px 0px 0px 1px#8b8b”,
});
常量shadowColor=“#a057”;
常量列=(道具:任意)=>{
函数findindex(val:any,pt:any){
const list=pt?props.possibleTags:props.tags;
return list.findIndex((item:any)=>val==item.name);
}
函数findindexofhelptext(val:any,pt:any){
const list=pt;
return list.findIndex((item:any)=>val==item.language);
}
返回(
{Object.keys(props.tags).map((key,i)=>
{props.tags[i].name}
)}
props.onDeleteColumn(props.index)}type=“button”style={{{填充:“8px 16px”,boxShadow:“2px 2px 2px 1px”+阴影颜色}}className=“btn btn danger btn ROLLED”>
);
};
常量重新排序=(列表:任意,起始索引:任意,结束索引:任意)=>{
const result=Array.from(列表);
常数[移除]=结果拼接(起始索引,1);
结果:拼接(末端索引,0,移除);
返回结果;
};
接口SetColumnsResponse扩展了HttpHelper.ResponseData{columns:any;}
类CrmConnectorColumns扩展React.Component{
建造师(道具:道具){
超级(道具);
this.moveColumn=this.moveColumn.bind(this);
此.state={
孤岛加载:是的,
isSaving:错,
canSave:false,
errorColor:“危险”,
字段:{columns:[]},
deleteModalActive:false,
configTagModalActive:false,
previewModalActive:false,
activeTag:{name:,属性:[{name:,value:}]},
可能的情况:[
{名称:“主要”,状态:“新”,帮助文本:[
{语言:“nl”,帮助文本:“Dit是de主键”},
{语言:“en”,帮助文本:“这是主键”}
],属性:[],使用:1},
{名称:“副标题”,状态:“新建”,帮助文本:[
{语言:“nl”,帮助文本:“Dit是van een记录的子项”},
{语言:“en”,帮助文本:“这是一条记录的字幕”}
],属性:[],使用:1},
{名称:“URL”,状态:“新建”,帮助文本:[
{语言:“nl”,帮助文本:“De waarde wordt gezien als link.”,
{语言:“en”,帮助文本:“值成为链接。”}
],属性:[
{名称:“链接”,状态:“新建”,帮助文本:[
{语言:“nl”,帮助文本:“链接krijgt deze waarde.Voorbeeld waarde is\”http://www.google.nl?search=[naam]\“.de waarde van\”[naam]\“wordt ingevuld.”,
{language:“en”,helptext:“链接获取此值。示例值为\”http://www.google.nl?search=[name]\”。填充\“[name]\”的值。“}
]}
],使用:undefined},
{名称:“标题”,状态:“新”,帮助文本:[
{语言:“nl”,帮助文本:“Dit是van een记录的Hoofditel”},
{语言:“en”,帮助文本:“这是记录的主要标题”}
],属性:[],使用:1},
{姓名:“电话”,状态:“新”,帮助文本:[
{语言:“nl”,帮助文本:“De waarde wordt gezien als telefoonnummer”},
{语言:“en”,帮助文本:“值变为电话号码”}
],属性:[],使用:undefined},
{名称:“按钮”,状态:“新建”,帮助文本:[
{语言:“nl”,帮助文本:“Uiterlik van een knop”},
{语言:“en”,帮助文本:“值变成按钮”}
],属性:[],使用:undefined},
{名称:“电子邮件”,状态:“新建”,帮助文本:[
{语言:“nl”,帮助文本:“De waarde wordt gezien als电子邮件地址”},
{语言:“en”,帮助文本:“该值成为电子邮件地址”}
],属性:[],使用:undefined},
{名称:“图像”,状态:“新建”,帮助文本:[
{语言:“nl”,帮助文本:“De waarde wordt als afbeelding weergegeven”},
{语言:“en”,帮助文本:“值显示为图像”}
],属性:[],使用:undefined},
{名称:“HTML”,状态:“新建”,帮助文本:[
{语言:“nl”,帮助文本:“De waarde wordt gezien als HTML”},
{语言:“en”,帮助文本:“值被视为自定义HTML”}
],属性:[
{名称:“HTML代码”,状态:“新建”,帮助文本:[
{语言:“nl”,帮助文本:“Vul hier je自定义HTML代码in.De waarde tussen De[]word vervangen door De data.”,
{language:“en”,helptext:“在此处输入自定义HTML。将替换[]之间的值作为值。”}
]}
],使用:undefined}
]
};
this.onDragEnd=this.onDragEnd.bind(this);
}
onDragEnd(结果:任何){
//在columns表之外删除
如果(!result.destination){