#vue.js #vuedraggable
Вопрос:
Я пытаюсь создать простой конструктор опросов с возможностью перетаскивания Vue3 и Vue. Все идет хорошо, пока я не попытаюсь создать вопрос с множественным выбором. Этот тип вопросов имеет свой собственный сортируемый список возможных ответов. Когда я добавляю еще один вопрос с множественным выбором, он затем извлекается из того же списка, что имеет смысл, но я попытался использовать v-if для проверки идентификатора родителей на соответствие идентификатору выбора..
В принципе, если я добавлю новый выбор, он добавится ко всем вопросам с множественным выбором, что имеет смысл, но как мне сохранить его в текущем пункте, в котором я нахожусь?
Есть какие-нибудь идеи? Я знаю, что код-это беспорядок, он будет переработан, как только он заработает.
<template>
<div class="p-4">
<div class="container mx-auto rounded-md grid grid-cols-12 gap-4 h-full">
<div class="col-span-4 p-3 flex flex-col min-h-screen bg-gray-200 shadow-md rounded-md">
<div class="text-lg font-bold w-full bg-blue-600 text-white rounded-md p-2 mb-4">Builder your survey</div>
<div class="sticky top-4">
<div class="text-lg font-bold">Components</div>
<draggable
class="p-2 rounded-md"
:list="componentsList"
:group="{ name: 'questions', pull: 'clone', put: false, sort: false }"
:clone="cloneItem"
sort: false
@change="log"
item-key="id"
>
<template #item="{ element }">
<div
class="bg-gray-300 p-4 rounded-md mt-2 shadow-sm hover:shadow-md cursor-pointer border border-blue-800 border-dashed"
>
{{ element.name }}
</div>
</template>
</draggable>
</div>
</div>
<div class="col-span-8 flex p-3 flex-col bg-white shadow-md rounded-md">
<div class="text-lg font-bold pt-4">Survey</div>
<draggable
class="w-full h-full border border-blue-400 rounded-md p-2 flex flex-col flex-1"
:list="questionsList"
group="questions"
@change="log"
handle=".handle"
itemKey="name index"
>
<template #item="{ element, index }">
<div>
<div v-if="element.name == 'Single Line of Text'" class="bg-gray-300 p-2 rounded-md mt-2 mb-2 shadow-lg hover:shadow-md">
<div class="w-full text-sm text-left">{{ element.name }} {{element.id}}</div>
<div class="flex justify-between items-center p-2 bg-gray-200 rounded-md mb-4">
<div class="w-10 font-bold hidden">Q{{ index 1 }}</div>
<div class="w-full pr-4">
<input
type="text"
class="w-full p-2 bg-transparent flex-grow"
placeholder="Question title here..."
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div @click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
<div>
<input
type="text"
class="w-full p-2 rounded-md border border-gray-400"
placeholder="User response will go here"
/>
</div>
<div class="text-left flex justify-between items-center p-2 bg-gray-200 rounded-md mt-2">
<div class="flex items-center">
<div><input type="checkbox" class="mr-2" /></div>
<div>Required?</div>
</div>
</div>
</div>
<!-- START problem area -->
<div v-else-if="element.name == 'Multiple Choice'" class="bg-gray-300 p-2 rounded-md mt-2 mb-2 shadow-lg hover:shadow-md">
<div class="w-full text-sm text-left">{{ element.name }} {{element.id}}</div>
<div class="flex justify-between items-center p-2 bg-gray-200 rounded-md mb-4">
<div class="w-10 font-bold hidden">Q{{ index 1 }}</div>
<div class="w-full pr-4">
<input
type="text"
class="w-full p-2 bg-transparent flex-grow"
placeholder="Question title here..."
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div @click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
<div class="flex items-center ">
<draggable
class="p-2 rounded-md w-full"
:list="multipleChoiceList"
:group="{ name: 'choice', pull: false, put: false, sort: true }"
sort: true
handle=".handle"
@change="log"
item-key="question"
>
<template #item="{ element }">
<div
class="bg-blue-100 p-4 flex items-center justify-start rounded-md mt-2 shadow-sm hover:shadow-md cursor-pointer w-full"
>
<div class="flex items-center flex-grow"
>
<input type="checkbox" class="w-6 h-6">
<input
type="text"
class="p-2 bg-transparent flex-grow"
placeholder="Add choice here"
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-1x mr-2"></i>
</div>
<div @click="remove(index)">
<i class="las la-trash-alt text-red-800 la-1x cursor-pointer"></i>
</div>
</div>
</div>
</template>
<template #footer>
<div>
<button class="p-2 bg-blue-300 mt-2 rounded-md" @click="addChoice(element.id)">Add</button>
</div>
</template>
</draggable>
</div>
<div class="text-left flex justify-between items-center p-2 bg-gray-200 rounded-md mt-2">
<div class="flex items-center">
<div><input type="checkbox" class="mr-2" /></div>
<div>Required?</div>
</div>
</div>
</div>
<!-- END problem area -->
<div v-else-if="element.name == 'Open Ended'" class="bg-gray-300 p-2 rounded-md mt-2 mb-2 shadow-lg hover:shadow-md">
<div class="w-full text-sm text-left">{{ element.name }} {{element.id}}</div>
<div class="flex justify-between items-center p-2 bg-gray-200 rounded-md mb-4">
<div class="w-10 font-bold hidden">Q{{ index 1 }}</div>
<div class="w-full pr-4">
<input
type="text"
class="w-full p-2 bg-transparent flex-grow"
placeholder="Question title here..."
v-model="element.text"
/>
</div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div @click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
<div>
<textarea
class="h-32 w-full w-full p-2 rounded-md border border-gray-400"
></textarea>
</div>
<div class="flex items-center">
<div>Max Length</div>
<div>
<input
type="number"
class="mr-2 w-20 border border-gray-400 p-2 rounded-md ml-2"
/>
</div>
</div>
<div class="text-left flex justify-between items-center p-2 bg-gray-200 rounded-md mt-2">
<div class="flex items-center">
<div><input type="checkbox" class="mr-2" /></div>
<div>Required?</div>
</div>
</div>
</div>
<div v-else-if="element.name == 'Divider'">
<div class="flex items-center">
<div class="flex-grow border-t border-black mx-4"> </div>
<div class="flex ">
<div class="cursor-pointer">
<i class="handle las la-arrows-alt la-2x mr-2"></i>
</div>
<div @click="remove(index)">
<i class="las la-trash-alt text-red-800 la-2x cursor-pointer"></i>
</div>
</div>
</div>
</div>
</div>
</template>
</draggable>
</div>
</div>
</div>
</template>
См. Метод клонирования, который присваивает случайное число в качестве идентификатора
<script>
import draggable from "vuedraggable";
export default {
name: "Survey",
components: {
draggable,
},
data() {
return {
drag: false,
componentsList: [
{ name: "Single Line of Text", type: "question", text: "", id: 1 },
{ name: "Multiple Choice", type: "question", text: "", id: 2 },
{ name: "Matrix", type: "question", text: "", id: 3 },
{ name: "Open Ended", type: "question", text: "", id: 4 },
{ name: "Divider", type: "component", id: 9 },
],
questionsList: [],
multipleChoiceList: [
{text: "text A", type:"choice", question:"32"},
{text: "text B", type:"choice", question:"1"},
{text: "text A", type:"choice", question:"2"} ]
};
},
methods: {
onEnd: function(evt) {
console.log(evt);
},
log: function(evt) {
console.log(evt);
},
addChoice(id) {
this.multipleChoiceList.push({ text: "Choice " id, type: "choice", question:id });
console.log(this.multipleChoiceList);
},
remove(index) {
this.questionsList.splice(index, 1);
},
cloneItem({ id, name, type }) {
return {
name: name,
id: Math.ceil(Math.random()*100),
text: "",
type: type,
};
}
},
mounted() {
// console.log("mounted");
},
};
</script>