У меня есть проект, включающий очень простой редактор, используемый для перетаскивания дорожек и соединения их путем привязки. Вот как выглядит компонент трека:
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
Реквизит не устанавливается программно ⇐ Javascript
Форум по Javascript
1771097822
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;
};
};
Подробнее здесь: [url]https://stackoverflow.com/questions/79888595/props-arent-being-set-programmatically[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия