Я только начал использовать составной API и <script setup>
блок и атрибут. Пока мне это нравится (из vue 2), но у меня была эта странная проблема, с которой я не могу справиться.
Я извлекаю объект JSON из своей базы данных, который содержит атрибуты (пары ключ: значение). Поскольку ключ является динамическим (думаю, { color:"blue", size:"medium" }
), мне нужно создать новый объект и добавить каждый атрибут в свой собственный объект, указав, какой из них является ключом, а какой — значением. Итак, { color:"blue"}
становится: { key: "color", value: "blue }
, что позволяет мне привязать его к входным данным в моем <template>
. Когда страница загружается, она преобразует атрибуты в новый объект и отображает их во входных данных.
Если пользователь хочет добавить атрибут, он может нажать кнопку, чтобы создать новую «строку» для атрибутов. Проблема в том, что когда они нажимают кнопку «плюс», объект атрибутов обновляется, но не отражается на форме (не реактивный). Я честно не уверен, почему. Вот мой <script>
:
<script setup>
import { computed, reactive } from "vue";
import { getProductByID } from "@/composables/products";
const props = defineProps({
productid: String,
});
const { product, error, loadProduct} = getProductByID(props.productid);
loadProduct();
const attributes = reactive({
english: computed(() => {
if (product.value.attributes && Object.keys(product.value.attributes).length > 0) {
let newValues = [];
for (const [key, value] of Object.entries(product.value.attributes)) {
let s = {};
s["key"] = key;
s["value"] = value;
newValues.push(s);
}
return newValues;
}
return {};
})
});
ПРИМЕЧАНИЕ: товар, возвращенный из сборного комплекта, упакован в ref{}
:
import axios from "axios";
import { ref } from "vue";
const product = ref({});
const error = ref(null);
...
return {product, error, loadProduct}
Атрибуты привязаны к входу правильно:
<div id = "attributes">
<!-- English Attributes -->
<div>
<div>
<label>Attributes (property : value) </label>
<button @click.prevent = "addAttributeInput">
<span class = "icon">
<i class = "fas fa-plus"></i>
</span>
</button>
</div>
<div v-for = "(attribute, index) in attributes.english" :key = "index">
<div>
<input v-model = "attributes.english[index]['key']" placeholder = "attribute" />
</div>
<div class = "control">
<span>:</span>
</div>
<div>
<input v-model = "attributes.english[index]['value']" placeholder = "value" />
</div>
<button @click.prevent = "removeAttributeInput(key)">
<span class = "icon">
<i class = "fas fa-minus"></i>
</span>
</button>
</div>
</div>
</div>
Если пользователь хочет добавить (или удалить) атрибут, есть кнопка, которая добавляет пустой объект к объекту attributes.english
:
function addAttributeInput() {
attributes.english.unshift({"key":"", "value":""});
}
function removeAttributeInput(index) {
attributes.english.splice(index, 1);
}
Когда я нажимаю эти кнопки, он изменяет объект attribute.english (я вижу его в инструментах vue в браузере), но не обновляет форму реактивно. Обертывание объекта attributes
с помощью reactive()
не делает его реактивным?
🤔 А знаете ли вы, что...
JavaScript является одним из трех основных языков веб-разработки, вместе с HTML и CSS.
Проблема с вашим кодом заключается в том, что вы не можете изменять реквизиты computed()
с помощью v-model
(если он не доступен для записи). Поэтому это не может работать.
Конечно, есть несколько вариантов решения вашей проблемы. Я сделал Stackblitz, чтобы показать, как это сделать с использованием watch()
, который устанавливает значение ref()
.
Это зависит от варианта использования, но может быть лучше использовать записываемый вычисляемый.