JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://unpkg.com/vue"></script>
<section id="app">
<content-editor></content-editor>
</section>
<template id="content-list-template">
<section class="content-list">
<div v-for="(currentView, index) in views" :key="currentView.index">
<component :is="currentView.type" :model="currentView.model" :update="updateContent(index)"></component>
<a v-on:click="removeContent(index)">Remove</a>
</div>
</section>
</template>
<template id="content-editor">
<section class="content-editor">
<content-list :views="views" :remove="removeContentBlock" :update="updateContentBlock"></content-list>
<button v-on:click="newContentBlock()">New Content</button>
</section>
</template>
<template id="content-longtext">
<div class="content-longtext">
<textarea :value="inputData" v-on:input="updateContent"></textarea>
</div>
</template>
<template id="content-image">
<div class="content-image">
<input type="file" />
</div>
</template>
JavaScript
Vue.component('content-longtext', {
template: '#content-longtext',
props: {
model: { type: String, required: true },
update: { type: Function, required: true }
},
data() {
return {
inputData: this.model
}
},
methods: {
updateContent(event) {
this.update(event.target.value)
}
},
})
Vue.component('content-image', {
template: '#content-image',
})
Vue.component('content-list', {
template: '#content-list-template',
props: {
remove: { type: Function, required: true },
update: { type: Function, required: true },
views: { type: Array, required: true }
},
methods: {
removeContent(index) {
this.remove(index)
},
updateContent(index) {
return (content) => this.update(index, content)
},
},
})
Vue.component('content-editor', {
template: '#content-editor',
data() {
return {
views: [
{index: 0, type: 'content-longtext', model: 'test1'},
{index: 1, type: 'content-longtext', model: 'test2'},
{index: 2, type: 'content-longtext', model: 'test3'},
{index: 3, type: 'content-longtext', model: 'test4'},
{index: 4, type: 'content-longtext', model: 'test5'},
],
}
},
methods: {
newContentBlock(type) {
this.views.push({index: this.views.length, type: 'content-longtext', model: ''})
},
updateContentBlock(index, model) {
this.views[index].model = model
},
removeContentBlock(index) {
this.views
.splice(index, 1)
.map((view, index) => view.index = index)
},
},
})
let app = new Vue({
el: '#app'
})