Я узнаю больше о Knockout.js. Я хочу добавить изображения к своим текстовым данным и отобразить правильный на основе ссылки на изображение, предоставленной в массиве с соответствующими данными. Я хочу, чтобы за раз отображался только один набор, другими словами, он заменяет данные. Я пока не совсем понимаю, как работает привязка данных и как все отображается. Я спотыкаюсь, пытаясь понять это.
То, что я вроде бы понял, это текстовая часть, но я потерялся при добавлении изображений на основе наборов ниже.
Вот краткий пример моих данных:
const story =
//-------------------------------Initiate Chat
{"1":{"text":"Pick a chat",
"image":"http://placekitten.com/300/200",
"choices":[{"choiceText":"Pick This","storyLink":"2"},{"choiceText":"no pick this","storyLink":"3"},{"choiceText":"nono this one","storyLink":"4"},{"choiceText":"dont pick this","storyLink":"5"},]},
//-------------------------------Chat 1 test
"2":{"text":"Kittens",
"image":"https://placekitten.com/300/100",
"choices":[{"choiceText":"Oops. Scared them.","storyLink":"3"}]},
"3":{"text":"They are no longer scared",
"image":"https://placekitten.com/300/100",
"choices":[{"choiceText":"Poor things.","storyLink":"3"}]},
}
Пример рабочего кода помог бы мне больше всего. Я продолжаю получать сообщение об ошибке «Невозможно обработать привязку», когда пытаюсь понять это. Кажется, я не могу найти конкретных примеров, когда изображения вызываются вместе с другими данными, такими как текст, как показано выше. Я ценю помощь!
Например: Knockout Image Не отображается при одновременной привязке изображения и текста
такого рода ответы на мой вопрос, но я не уверен, как это сделать с массивом. Должен ли я использовать forEach?
Вы используете тег с привязкой нокаута attr
для отображения изображений. Пример:
<img data-bind = "attr: {src: 'https://placekitten.com/300/100'}">
См. этот рабочий пример:
https://jsfiddle.net/martlark/9v028d4z/34/
Я считаю хорошей идеей ввести некоторые модели представления, которые упростят работу с вашим форматом истории.
В приведенном ниже примере я создал два:
StoryVM
ChoiceVM
onClick
, который устанавливает активную историю для каждого выбора,Как только вы правильно сопоставите URL-адреса изображений между вариантами выбора и фрагментами основной истории, вы можете использовать привязку attr: { src }
, чтобы применить ее к изображению.
Чтобы предотвратить повреждение изображений, когда src недоступен, я заключил тег <img>
в привязку if
.
const StoryVM = (model, startId) => {
const activeStoryId = ko.observable(startId);
const activeStory = ko.pureComputed(() => {
const data = model[activeStoryId()]
return {
...data,
choices: data.choices.map(ChoiceVM)
};
});
const ChoiceVM = ({
choiceText,
storyLink,
}) => {
return {
image: storyModel[storyLink]?.image,
text: choiceText,
onClick: () => {
activeStoryId(storyLink);
}
}
}
return activeStory;
}
const storyModel = {"1":{"text":"Pick a chat","image":"http://placekitten.com/300/200","choices":[{"choiceText":"Pick This","storyLink":"2"},{"choiceText":"no pick this","storyLink":"3"},{"choiceText":"nono this one","storyLink":"4"},{"choiceText":"dont pick this","storyLink":"5"}]},"2":{"text":"Kittens","image":"https://placekitten.com/300/100","choices":[{"choiceText":"Oops. Scared them.","storyLink":"3"}]},"3":{"text":"They are no longer scared","image":"https://placekitten.com/200/100","choices":[{"choiceText":"Poor things.","storyLink":"3"}]}};
ko.applyBindings({
story: StoryVM(storyModel, "1")
});
.Choices {
display: flex;
gap: 1rem;
}
.Choice {
display: flex;
flex-direction: column;
width: 200px;
height: 150px;
justify-content: flex-end;
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind = "with: story">
<!-- ko if: image -->
<img data-bind = "attr: { src: image }">
<!-- /ko -->
<h2 data-bind = "text: text"></h2>
<div data-bind = "foreach: choices" class = "Choices">
<div class = "Choice">
<!-- ko if: image -->
<img data-bind = "attr: { src: image }">
<!-- /ko -->
<button data-bind = "click: onClick, text: text"></button>
</div>
</div>
</div>
Спасибо вам за помощь! Я взволнован, чтобы играть с этим. Супер полезно!
У меня есть еще один вопрос, связанный с тем, как вы настроили это сейчас, когда оно у меня работает. Если бы я хотел создать функцию, которая вызывает текст в наборе данных и заставляет его начать его печатать (например, у меня есть функция таймера), как бы я мог сделать это без использования клика/события? В старой версии можно было сказать «имя массива [0]», и он перепрыгивал туда, когда истекал таймер. Я попытался изменить activeStoryID на соответствующий чат, но он не «запускает» этот чат, поэтому я что-то упускаю.
Я не думаю, что понимаю, что вы имеете в виду. Можете ли вы показать мне код, который вы пытаетесь запустить?
Конечно! Вот фрагмент. Здесь функция вызывается после истечения времени таймера. Это прекрасно работает. setTimeout(wakeUp, 1000); function wakeUp() { console.info("wakeup"); activeStory = 3 console.info(activeStory); }
Что он делает прямо сейчас, как в вашем примере, так это привязка клика активирует изменение данных из одного набора в другой. Я хочу сделать это в этой функции, но я не уверен, что мне нужно изменить или сказать ей, чтобы она вызывала ее. Я думал, что изменение Active Story сделает это. @user3297291 user3297291 Имеет ли это больше смысла?
Чтобы обновить наблюдаемое значение, вы пишете activeStory(3)
, а не activeStory = 3
. Чтобы прочитать его значение, вы пишете activeStory()
, а не activeStory
. Итак: activeStory(3); console.info(activeStory())
. Смотрите этот раздел документов
Оххххххх. Спасибо, что объяснили это! Я подумал, что испортил синтаксис. Я запутался, читая документацию. Я все еще довольно новый кодер, поэтому я ценю дополнительную руку. @user3297291
Я и не знала, что это вещь, спасибо!