简体   繁体   English

如何动态创建javascript表单元素

[英]How to create javascript form elements dynamically

I have a vuejs page and I am creating DOM inputs dynamically and I want to bind them with a set of 3 form variables to catch the data.我有一个 vuejs 页面,我正在动态创建 DOM 输入,我想将它们与一组 3 个表单变量绑定以捕获数据。 I don't know how many sets of inputs they will be created from the beginning to initialize the form entries.我不知道他们会从一开始就创建多少组输入来初始化表单条目。 The form is created with useForm on the setup() section of Vue.该表单是在 Vue 的 setup() 部分使用 useForm 创建的。 Below are snips of the code.下面是代码的片段。

<template>
    <app-layout>
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">
                {{ title }}
            </h2>
        </template>
        <div class="py-12">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
                    <div class="audio_edit">
                        <form @submit.prevent="form.post('/pppaudio/newProcessedAudio')">
                            <div class="pp_title">
                                <label style="font-weight: bold">
                                    Title:
                                </label>
                                <label for="title">{{ title }}</label>
                            </div>
                            <div class="pp_audio">
                                <div id="waveform"></div>
                                <div id="wave-timeline"></div>
                                <div class="playButton">
                                    <Button data-action="play" type="button">
                                        <span id="play">
                                            <i class="glyphicon glyphicon-play"></i>
                                            Play
                                        </span>
                                        <span id="pause" style="display: none">
                                            <i class="glyphicon glyphicon-pause"></i>
                                            Pause
                                        </span>
                                    </Button>
                                </div>
                            </div>
                            <div class="pp_transcript flex flex-col">
                                <label style="font-weight: bold">
                                    Transcript:
                                </label>
                                {{ transcript }}
                            </div>
                            <div id="region_block" ref="reg_block" >
                                <div class="region">
                                    <div id="copyTextButton" class="copyButton">
                                        <Button v-on:click="getText" type="button">Copy Marked Text</Button>
                                    </div>
                                    <div class="pp_new_transcript flex flex-col">
                                        <label style="font-weight: bold">
                                            New Transcript:
                                        </label>
                                        <textarea id="selectedText" rows="5" class="selectedTextInput h-full" v-model="form.selectedText" />
                                    </div>
                                    <div class="pp_start-stop">
                                        <label for="start" style="font-weight: bold">
                                            Start:
                                        </label>
                                        <input id="start" v-model="form.start" disabled/>
                                        <label for="stop" style="font-weight: bold">
                                            Stop:
                                        </label>
                                        <input id="stop" v-model="form.stop" disabled/>
                                    </div>
                                    <div id="submit_button">
                                        <Button>Submit</Button>
                                    </div>
                                </div>
                            </div>

                            <div id="return_back">
                                <Button v-on:click="goBack" type="button">Back</Button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </app-layout>
</template>

<script>
import AppLayout from "../../Layouts/AppLayout";
import Label from "../../Jetstream/Label";
import Button from "../../Jetstream/Button";
import {InputFacade} from 'vue-input-facade';
import WaveSurfer from 'wavesurfer.js';
import RegionPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.regions.js';
import TimeLine from 'wavesurfer.js/dist/plugin/wavesurfer.timeline.js';
import {useForm} from '@inertiajs/inertia-vue3';
import Vue from 'vue'

export default {
    setup() {
        const form = useForm({
            title: null,
            selectedText: null,
            start: null,
            stop: null,
        })

        return {form}
    },
    components: {Button, Label, AppLayout, InputFacade},
    methods: {
        getText() {
            this.newTranscript = window.getSelection().toString();
            this.form.selectedText = this.newTranscript;
            this.form.title = this.title;
        },
        copyValues(start, stop) {
            this.form.start = start;
            this.form.stop = stop;
        },
        goBack() {
            let formData = new FormData();
            formData.append('id', localStorage.id);

            axios.post('/pppaudio/goBack',
                formData, {
                    headers: {
                        'Content-Type': 'multipart/form-data'
                    }
                }
            ).then( (response) => {
                if (response.data.status === 'success') {
                    window.location.href = response.data.url;
                }
            }).catch(error => {
                console.log("ERRRR:: ", error.response.data);
            });
        }
    },
    mounted() {
        if (localStorage.title) {
            this.title = localStorage.title;
        }
        if (localStorage.path) {
            this.path = localStorage.path;
        }
        if (localStorage.transcript) {
            this.transcript = localStorage.transcript;
        }

        const wavesurfer = WaveSurfer.create({
            container: '#waveform',
            waveColor: 'violet',
            progressColor: 'purple',
            scrollParent: true,
            plugins: [
                RegionPlugin.create({
                    dragSelection: true
                }),
                TimeLine.create({
                    container: '#wave-timeline'
                })
            ]
        });

        wavesurfer.load('../storage/preprocessed-audio/' + this.path);

        let play = false;

        wavesurfer.on('region-click', (region, e) => {
            e.stopPropagation();
            // Play on click, loop on shift click
            if (play) {
                wavesurfer.pause();
                play = false;
            } else {
                region.play();
                play = true;
            }
            // console.log(this.form.title);
           this.copyValues(region.start, region.end);
        });

        wavesurfer.on('region-created', (region, e) => {
            console.log(region.id.substring(10))
            let regionNode = document.createElement("div")
            regionNode.className = "region"
            let regionTitle = document.createElement("div")
            regionTitle.className = "regionTitle"
            regionTitle.innerHTML = region.id
            regionTitle.style.fontWeight = "bold"
            regionNode.appendChild(regionTitle)
            let color = () => Math.random() * 256 >> 0;
            let col = `${color()}, ${color()}, ${color()}`
            regionTitle.style.color = 'rgb('+col+')';
            region.color = 'rgba('+ col + ', 0.1)';
            let copyButtonDiv = document.createElement("div")
            copyButtonDiv.className = "copyTextButton"
            let copyButton = document.createElement("Button")
            copyButton.className = "inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring focus:ring-gray-300 disabled:opacity-25 transition"
            let copyButtonText = document.createTextNode("Copy Marked Text")
            copyButton.appendChild(copyButtonText)
            copyButton.addEventListener('click', this.getText)
            let cpBtnType = document.createAttribute("type")
            cpBtnType.value = "button"
            copyButton.setAttributeNode(cpBtnType)
            copyButtonDiv.appendChild(copyButton)
            regionNode.appendChild(copyButtonDiv)
            let newTranscriptDiv = document.createElement("div")
            newTranscriptDiv.className = "pp_new_transcript flex flex-col"
            let newTransLabel = document.createElement("label")
            newTransLabel.innerText = "New Transcript:"
            newTransLabel.style.fontWeight = "bold"
            let selectTextArea = document.createElement("textarea")
            selectTextArea.id = "selectedText"
            selectTextArea.className = "selectedTextInput h-full"
            let selectTextAreType = document.createAttribute("rows")
            selectTextAreType.value = "5"
            selectTextArea.setAttributeNode(selectTextAreType)
            newTranscriptDiv.appendChild(newTransLabel)
            newTranscriptDiv.appendChild(selectTextArea)
            regionNode.appendChild(newTranscriptDiv)
            let startStopDiv = document.createElement("div")
            startStopDiv.className = "pp_start-stop"
            let startLabel = document.createElement("label")
            startLabel.innerText = "Start:"
            startLabel.style.fontWeight = "bold"
            let startLabelType = document.createAttribute("for")
            startLabelType.value = "start"
            startLabel.setAttributeNode(startLabelType)
            let startInput = document.createElement("input")
            startInput.id = "start"
            let startInputType = document.createAttribute("disabled")
            startInput.setAttributeNode(startInputType)
            let stopLabel = document.createElement("label")
            stopLabel.innerText = "Stop:"
            stopLabel.style.fontWeight = "bold"
            let stopLabelType = document.createAttribute("for")
            stopLabelType.value = "stop"
            stopLabel.setAttributeNode(stopLabelType)
            let stopInput = document.createElement("input")
            stopInput.id = "stop"
            let stopInputType = document.createAttribute("disabled")
            stopInput.setAttributeNode(stopInputType)
            startStopDiv.appendChild(startLabel)
            startStopDiv.appendChild(startInput)
            startStopDiv.appendChild(stopLabel)
            startStopDiv.appendChild(stopInput)
            regionNode.appendChild(startStopDiv)
            let submitBtnDiv = document.createElement("div")
            submitBtnDiv.id = "submit_button"
            let submitButton = document.createElement("Button")
            let submitButtonText = document.createTextNode("Submit")
            submitButton.className = "inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring focus:ring-gray-300 disabled:opacity-25 transition"
            submitButton.appendChild(submitButtonText)
            submitBtnDiv.appendChild(submitButton)
            regionNode.appendChild(submitBtnDiv)
            // this.$set()


            document.querySelector('#region_block').appendChild(regionNode)
        })

        let playButton = document.querySelector('#play');
        let pauseButton = document.querySelector('#pause');
        wavesurfer.on('play', function() {
            playButton.style.display = 'none';
            pauseButton.style.display = '';
        });
        wavesurfer.on('pause', function() {
            playButton.style.display = '';
            pauseButton.style.display = 'none';
        });

        playButton.addEventListener('click', function () {
            wavesurfer.play()
        })

        pauseButton.addEventListener('click', function () {
            wavesurfer.pause()
        })

    },
    data() {
        return {
            title: '',
            path: '',
            transcript: '',
            selectedText: '',
            newTranscript: '',
            start: '',
            stop: ''
        }
    }
}
</script>

<style>
.audio_edit {
    padding: 10px;
}

.pp_title, .pp_audio, .copyButton, .pp_transcript, .pp_new_transcript, .pp_start-stop, #wave-timeline, #submit_button {
    padding-bottom: 10px;
}

.region {
    border-top: 3px solid black;
    border-bottom: 3px solid black;
    padding-top: 3px;
    margin-bottom: 3px;
}

.pp_new_transcript {
    display: flex;
    width: 100%;
}

.selectedTextInput {
    -webkit-box-flex:1;
    -webkit-flex:1;
    -ms-flex:1;
    flex:1;
    border: none;
}

</style>
  1. Whenever you need some HTML to repeat in Vue, use v-for .每当您需要在 Vue 中重复一些 HTML 时,请使用v-for In the example below I'm using it with component在下面的示例中,我将它与组件一起使用

  2. Using createElement in Vue is rarely needed and should be avoided .在 Vue 中使用createElement很少需要,应该避免 If you think about my example below, you should see that whole wavesurfer.on('region-created') part can be just replaced by just pushing new Region object into an array which is used in v-for如果您考虑下面的示例,您应该会看到整个wavesurfer.on('region-created')部分可以通过将新的 Region 对象推送到v-for使用的数组中来替换

 const app = Vue.createApp({ data() { return { forms: [{ id: 1, selectedText: 'Hello', start: 0, stop: 4 }, { id: 2, selectedText: 'world', start: 6, stop: 10 }, ] } } }) app.component('my-form', { props: { form: { type: Object, required: true } }, template: ` <div class="region"> <div id="copyTextButton" class="copyButton"> <button type="button">Copy Marked Text</button> </div> <div class="pp_new_transcript flex flex-col"> <label style="font-weight: bold"> New Transcript: </label> <textarea id="selectedText" rows="5" class="selectedTextInput h-full" v-model="form.selectedText" /> </div> <div class="pp_start-stop"> <label for="start" style="font-weight: bold"> Start: </label> <input id="start" v-model="form.start" disabled/> <label for="stop" style="font-weight: bold"> Stop: </label> <input id="stop" v-model="form.stop" disabled/> </div> <div id="submit_button"> <button>Submit</button> </div> </div> ` }) app.mount('#app')
 <script src="https://unpkg.com/vue@3.1.4/dist/vue.global.js"></script> <div id='app'> <my-form v-for="form in forms" :key="form.id" :form="form"></my-form> </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM