Vue.js实战 调查问卷 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');
        }
    }
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。