Vue.js實戰(zhàn) 調查問卷 WebApp

項目:調查問卷WebApp
描述:制作一個簡單的調查問卷HTML 5小應用,每頁有一道題目,題目可以是單選題、多選題、填寫題等。

目錄結構

index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>WebApp</title>
</head>
<body>
<div id="app">
    <questionnaire :questions="questions" @submit="handleSubmit"></questionnaire>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="questionnaire.js"></script>
<script src="questions.js"></script>
<script src="mybutton.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            questions: [
                {
                    type: "radio",
                    title: "你的性別",
                    choices: ["男", "女"],
                    picked: ""
                },
                {
                    type: "multi",
                    title: "你的愛好",
                    choices: ['籃球', '足球', '羽毛球'],
                    picked: []
                },
                {
                    type: "typetext",
                    title: "自我介紹",
                    text: ""
                }
            ]
        },
        methods: {
            handleSubmit: function (e) {
                var text = "";
                text += "你是" + e[0].picked + "的\n";
                text += "你喜歡" + e[1].picked.join("和") + "\n";
                text += "你說'" + e[2].text + "'\n";
                alert(text);
            }
        }
    });
</script>
</body>
</html>

questionnaire.js:

Vue.component('questionnaire', {
    template: '\
    <div>\
        <div>{{ page + 1 }} / {{ count }}</div>\
        <div v-for="(item, index) in questions">\
            <radioselect v-show="page === index" v-if="item.type==\'radio\'" :name="\'q\' + (index + \'\')" :title="item.title" :choices="item.choices" @pick="handlePick(arguments)"></radioselect>\
            <multiselect v-show="page === index" v-else-if="item.type==\'multi\'" :name="\'q\' + (index + \'\')" :title="item.title" :choices="item.choices" @pick="handlePick(arguments)"></multiselect>\
            <typetext v-show="page === index" v-else :name="\'q\' + (index + \'\')" :title="item.title" @pick="handlePick(arguments)"></typetext>\
        </div>\
        <mybutton v-show="page === count -1" :banned="disabledSubmit" @click="handleSubmit">提交</mybutton>\
        <mybutton v-show="page < count -1" :banned="disabledNext" @click="handleNext">下一題</mybutton>\
        <mybutton v-show="page > 0" :banned="false" @click="handlePrev">上一題</mybutton>\
        <mybutton @click="handleReset" :banned="false">重置</mybutton>\
    </div>',
    props: {
        questions: {
            type: Array,
            default: function () {
                return [];
            }
        }
    },
    computed: {
        count: function () {
            return this.questions.length;
        }
    },
    data: function () {
        return {
            page: 0,
            disabledSubmit: true,
            disabledNext: true
        }
    },
    mounted: function () {
    },
    methods: {
        handleSubmit: function () {
            this.$emit('submit', this.questions);
        },
        handleNext: function () {
            if (this.page < this.count - 1) {
                this.page++;
                this.updateDisabledNext();
            }
        },
        handlePrev: function () {
            if (this.page > 0) {
                this.page--;
                this.updateDisabledNext();
            }
        },
        handleReset: function () {
            question = this.questions[this.page];
            switch (question.type) {
                case 'radio':
                    this.$children[this.page].curValue = "";
                    break;
                case 'multi':
                    this.$children[this.page].curValue = [];
                    break;
                case 'typetext':
                    this.$children[this.page].value = "";
                    break;
                default:
            }
        },
        handlePick: function (arguments) {
            question = this.questions[this.page];
            switch (question.type) {
                case 'radio':
                case 'multi':
                    this.questions[this.page].picked = arguments[0];
                    break;
                case 'typetext':
                    this.questions[this.page].text = arguments[0];
                    break;
                default:
            }
            this.updateDisabledNext();
            this.updateDisabledSubmit();
        },
        updateDisabledNext: function () {
            var flag = false;
            var item = this.questions[this.page];
            if (item.type === 'radio') {
                if (item.picked === "")
                    flag = true;
            } else if (item.type === 'multi') {
                if (item.picked.length < 2)
                    flag = true;
            } else {
                if (item.text.length < 10)
                    flag = true;
            }
            this.disabledNext = flag;
        },
        updateDisabledSubmit: function () {
            var flag = false;
            this.questions.forEach(function (item) {
                if (item.type === 'radio') {
                    if (item.picked === "")
                        flag = true;
                } else if (item.type === 'multi') {
                    if (item.picked.length < 2)
                        flag = true;
                } else {
                    if (item.text.length < 10)
                        flag = true;
                }
            });
            this.disabledSubmit = flag;
        }
    }
});

questions.js:

Vue.component('radioselect', {
    name: 'radioselect',
    props: {
        name: {
            type: String,
            default: "question0"
        },
        title: {
            type: String,
            default: "Question"
        },
        choices: {
            type: Array,
            default: function () {
                return ["C1", "C2", "C3"]
            }
        }
    },
    data: function () {
        var _this = this;
        var values = [];
        this.choices.forEach(function (item, index) {
            values.push(_this.name + (index + ''));
        });
        return {
            values: values,
            curValue: ""
        }
    },
    template: '\
        <div>\
            <span>{{ title }}</span>\
            <div v-for="(choice, index) in choices">\
                <input type="radio" v-model="curValue" :value="choices[index]" :id="values[index]">\
                <label :for="values[index]">{{ choice }}</label>\
            </div>\
        </div>\
        ',
    methods: {

    },
    watch: {
        curValue: function (val) {
            this.$emit('pick', val);
        }
    }
});

Vue.component('multiselect', {
    name: 'multiselect',
    props: {
        name: {
            type: String,
            default: "question0"
        },
        title: {
            type: String,
            default: "Question"
        },
        choices: {
            type: Array,
            default: function () {
                return ["C1", "C2", "C3"]
            }
        }
    },
    data: function () {
        var _this = this;
        var values = [];
        this.choices.forEach(function (item, index) {
            values.push(_this.name + (index + ''));
        });
        return {
            values: values,
            curValue: []
        }
    },
    template: '\
        <div>\
            <span>{{ title }}</span>\
            <div v-for="(choice, index) in choices">\
                <input type="checkbox" v-model="curValue" :value="choices[index]" :id="values[index]">\
                <label :for="values[index]">{{ choice }}</label>\
            </div>\
        </div>\
        ',
    methods: {

    },
    watch: {
        curValue: {
            handler: function (val) {
                this.$emit('pick', val);
            },
            deep: true
        }
    }
});

Vue.component('typetext', {
    name: 'typetext',
    props: {
        name: {
            type: String,
            default: "question0"
        },
        title: {
            type: String,
            default: "Question"
        },
        text: {
            type: String,
            default: ""
        }
    },
    data: function () {
        return {
            value: this.text
        }
    },
    template: '\
        <div>\
            <span>{{ title }}</span>\
            <div>\
                <textarea v-model="value">\
                </textarea>\
            </div>\
        </div>\
        ',
    methods: {},
    watch: {
        value: function (val) {
            this.$emit('pick', val);
        }
    }
});

mybutton.js:

Vue.component('mybutton', {
    props: {
        fontcolor: {
            type: String,
            default: "#000"
        },
        banned: {
            type: Boolean,
            default: true
        }
    },
    template: '\
    <div>\
        <button class="mybutton" @click="handleClick" :disabled="banned"><slot></slot></button>\
    </div>',
    methods: {
        getStyle: function () {
            return {
                color: this.fontcolor,
                ":active color": "#fff"
            }
        },
        handleClick: function () {
            this.$emit('click');
        }
    }
});
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容