Реквизит не устанавливается программноJavascript

Форум по Javascript
Ответить
Anonymous
 Реквизит не устанавливается программно

Сообщение Anonymous »

У меня есть проект, включающий очень простой редактор, используемый для перетаскивания дорожек и соединения их путем привязки. Вот как выглядит компонент трека:

import { currentID, station_length, to_connect_to } from "./stores.svelte";
import { edit } from "./stores.svelte";
import { tracks_arr } from "./stores.svelte";

import { tracksBorder } from "./stores.svelte";

import { detectSnapping } from "./stores.svelte";
import { somethingIsMoving, width_of_moving } from "./stores.svelte";
//Track data from tracks_arr
let {
//Constants (change on edit, not never)
number,
id,

length = 0,
slope = 0,

left,
top,
width,
height,
posClass,
//Connects property (an array object) contains the number
//values of the track's connecting tracks (indexes are the direction so
//at 0 is the track to the left and at 1 to the right).
//If they are empty (only one of them) the track connects to the
//next station, if not-defined, they are, well, not defined yet.
connects = ["","not-defined"],
//Reactives
status = 0,//Status of track: false - available, true - unavailable
tag = "",

} = $props();

let innerTag = $derived.by(() => {
if (!status) {return $tracks_arr[selfIndex].number}
});

let selfIndex = $derived($tracks_arr.findIndex(v => v.id == id));

let inner_top = $derived(top);

//Setting draggable logic
let moving = $state(false);

/**@param {MouseEvent} e*/
function onMouseMove(e) {
if (!($edit && moving)) {return};
if ((connects.includes(""))) {
$tracks_arr[selfIndex].posClass = (e.clientX < window.innerWidth/2 ? `connecting0` : `connecting1`);
$tracks_arr[selfIndex].connects = (e.clientX < window.innerWidth/2 ? ["","not-defined"] : ["not-defined",""]);
$tracks_arr[selfIndex].top = (e.clientY > $tracksBorder ? e.clientY : $tracksBorder);

$somethingIsMoving = false;
} else {
$tracks_arr[selfIndex].left = e.clientX - (window.innerWidth * ((length/$station_length)/2));//Centers x on the mouse
$tracks_arr[selfIndex].top = (e.clientY > $tracksBorder ? e.clientY : $tracksBorder);
};

$to_connect_to = id;
$width_of_moving = width;
};

/**@param {MouseEvent} e*/
function onMouseDown(e) {
moving = true;

$somethingIsMoving = true;
};
/**@param {MouseEvent} e*/
function onMouseUp(e) {
moving = false;

$somethingIsMoving = false;
};

-------------------------Important part--------------------------
//Snapping logic

function onRightSnap() {
if (($tracks_arr.length > 1) && $somethingIsMoving) {
let indexOfSnapping = $tracks_arr.findIndex(v => v.id == $to_connect_to);

$tracks_arr[indexOfSnapping].top = top;
$tracks_arr[indexOfSnapping].left = (!(connects.includes("")) ? (width + left + 4) : 0)
$tracks_arr = $tracks_arr;

moving = false;

};
};

function onLeftSnap() {
if (($tracks_arr.length > 1) && $somethingIsMoving) {
let indexOfSnapping = $tracks_arr.findIndex(v => v.id == $to_connect_to);

$tracks_arr[indexOfSnapping].top = top;
$tracks_arr[indexOfSnapping].left = (connects.includes("") ? (window.innerWidth - width - $width_of_moving - 4) : (left - $width_of_moving - 4))
$tracks_arr = $tracks_arr;

moving = false;

};
};
--------------------------------------------------------------------------


{#if connects.includes("")}


use:detectSnapping onrightsnap={onRightSnap} onleftsnap={onLeftSnap}

draggable="false" ondragstart={(/** @type {{ preventDefault: () => any; }} */ e) => e.preventDefault()}
id="parent" style="
--length: {length};
--station_length: {$station_length};"

style:color={status ? "red" : "#c2c2c2"}
style:top={`${top}px`}
bind:clientHeight={$tracks_arr[selfIndex].height}
bind:clientWidth={$tracks_arr[selfIndex].width}
class={posClass}
style:cursor={(moving && $edit ? "grabbing" : "default")}
>

e.preventDefault()}
style:background-color={status ? "red" : "#c2c2c2"};
>


{/if}

События rightsnap и leftsnap закодированы в глобальном файле store.svelte.js (это пример, который я использовал), и вся функция действия выглядит следующим образом (для упрощения — она просто создает два вымышленных прямоугольника по обе стороны от дорожки, которые слушают, если на них находится мышь, и запускают события соответственно):
/**@param {HTMLElement} node*/
export function detectSnapping(node) {
window.addEventListener("mousemove", handleMove);

/**@param {MouseEvent} e*/
function handleMove(e) {
const width = node.getBoundingClientRect().width;
const height = node.getBoundingClientRect().height;

const top = node.getBoundingClientRect().top;
const left = node.getBoundingClientRect().left;

if ((e.clientY > (top - 15)) && (e.clientY < (top + height + 15))) {
if ((e.clientX < (left + width + 15)) && (e.clientX > (left + width))) {node.dispatchEvent(new CustomEvent("rightsnap"));};

if ((e.clientX < left) && (e.clientX > (left - 15))) {node.dispatchEvent(new CustomEvent("leftsnap"))};
}
};
return {
destroy() {
window.removeEventListener("mousemove",handleMove)
}
}
};

Дорожки добавляются с помощью простой функции в другом компоненте, например:
function addTrack() {
$currentID += 1;
$currentID = $currentID;
newTrackObj.id = $currentID;

$tracks_arr.push($state.snapshot(newTrackObj));
$tracks_arr = $tracks_arr;

$showAddTRackMenu = false;
};

NewTrackObj — это всего лишь шаблон. Все работает хорошо, когда я добавляю треки вручную (записываю их прямо в массив перед запуском), и события срабатывают правильно.
Однако при настройке соответствующих свойств трека с помощью addTrack в его объекте в track_arr события срабатывают, но реквизиты не устанавливаются, следовательно, трек не привязывается к правильному местоположению.
Как ни странно, при обновлении исходного кода без перезагрузки страницы привязка происходит работает правильно, пока я не обновлю его снова.
Изменить: Также вот что я делаю в page.svelte:
{#each $tracks_arr as track (track.id)}

{/each}

Итак, я понял, что вы оба были правы, поэтому я выбрал гибридное решение, в котором я удалил локальные копии и вместо этого заменил все на $tracks_arr[selfIndex].someprop, одновременно используя метод перестройки, предложенный Майком. Я также реализовал этот класс следующим образом:
export class TrackClass {
number = $state("");
id = $state(0);

length = $state(0);
slope = $state(0);

left = $state(0);
top = $state(0);
width = $state(0);
height = $state(0);
posClass = $state(``);

connects = $state(["not-defined","not-defined"]);
status = $state(0);
tag = $state("");

constructor(data) {
this.number = data.number;
this.id = data.id;

this.length = data.length;
this.slope = data.slope;

this.left = data.left;
this.top = data.top;
this.width = data.width;
this.height = data.height;
this.posClass = data.posClass;

this.connects = data.connects;
this.status = data.status;
this.tag = data.tag;
}
};

А теперь добавляю треки вот так:
function addTrack() {

const newTrack = {
number : trackBindings.number,
id : $currentID,

length : trackBindings.length,
slope : trackBindings.slope,

left : 0,
top : $tracksBorder,
width : 0,
height : 0,
posClass : ``,

connects : trackKindObj[selectedKind],
status : 0,
tag : ""
};

$tracks_arr = [...$tracks_arr, new TrackClass(newTrack)];

$currentID += 1;
$currentID = $currentID;

$showAddTRackMenu = false;
};

Но по какой-то причине, хотя selfIndex оценивается правильно, как только я пытаюсь вызвать любое из событий моментальной привязки, я получаю сообщение «невозможно прочитать свойства неопределенного (чтение идентификатора)» TypeError. Вот что я делаю для функций событий:
function onRightSnap() {
if (($tracks_arr.length > 1) && $somethingIsMoving) {

$tracks_arr = $tracks_arr.map((track,index) => {
console.log(track,index);
(index === $to_connect_to ? {...track, top: $tracks_arr[selfIndex].top, left: ($tracks_arr[selfIndex].connects.includes("") ? ($tracks_arr[selfIndex].width + 4) : ($tracks_arr[selfIndex].left + $tracks_arr[selfIndex].width + 4))} : track)
});

moving = false;
};
};

function onLeftSnap() {
if (($tracks_arr.length > 1) && $somethingIsMoving) {

$tracks_arr = $tracks_arr.map((track,index) => {
(index === $to_connect_to ? {...track, top: $tracks_arr[selfIndex].top, left: ($tracks_arr[selfIndex].connects.includes("") ? ($tracks_arr[selfIndex].width - 4) : ($tracks_arr[selfIndex].left - $tracks_arr[selfIndex].width - 4))} : track)
});

moving = false;
};
};


Подробнее здесь: https://stackoverflow.com/questions/798 ... mmatically
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»