欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Vue.js学习笔记—调查问卷WebApp

程序员文章站 2022-05-18 17:16:44
...

参考《Vue,js》实战(梁灏编著)

基础篇的章节内容涵盖了Vue.js 2.x最常用的功能。如果不需要前端路由和自动化工程,已经可以利用这些内容做一些中小型项目了。在进入进阶篇之前,通过一个小项目加深对Vue.js基础知识的理解。

项目:调查问卷 WebApp

描述:

制作一个简单的调查问卷HTML5小应用,每页有一道题目,题目可以是单选题、多选题、填写题等,最终效果如下:Vue.js学习笔记—调查问卷WebApp

说明

每一页可以通过v-show或v-if在切换步骤时显示,点击重置,当前页的控件还原到初始状态。要对每页的数据进行校验,比如单选题必须要选择,多选题最少选择2项,最多选择3项,文本框输入不能少于100字,若当前页不满足验证要求,则下一步的按钮置灰,不可点击。

要求

按钮要制作成组件,可以控制颜色、状态(禁用),点击后传递一个自定义事件on-click。

项目代码

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>调查问卷WebAPP</title>
    <link rel="stylesheet" href="style.css" type="text/css">
</head>

<body>
    <div id="app" class="page" v-cloak>
        <div v-if="page === 1">
            <p>1.请问您的性别是:</p>
            <input type="radio" v-model="picked" value="male" id="male">
            <label for="male"></label>
            <input type="radio" v-model="picked" value="female" id="female">
            <label for="female"></label>
            <input type="radio" v-model="picked" value="none" id="none">
            <label for="none">保密</label>
            <div class="bottom">
                <next-step class="button" v-model="page"></next-step>
                <reset class="button" v-model="picked" :page="page"></reset>
            </div>
        </div>
        <div v-else-if="page === 2">
            <p>2.请选择您的兴趣爱好:</p>
            <input type="checkbox" v-model="checked" value="read" id="read">
            <label for="read">看书</label>
            <br>
            <input type="checkbox" v-model="checked" value="swim" id="swim">
            <label for="swim">游泳</label>
            <br>
            <input type="checkbox" v-model="checked" value="run" id="run">
            <label for="run">跑步</label>
            <br>
            <input type="checkbox" v-model="checked" value="movie" id="movie">
            <label for="movie">看电影</label>
            <br>
            <input type="checkbox" v-model="checked" value="music" id="music">
            <label for="music">听音乐</label>
            <br>
            <div class="bottom">
                <next-step class="button" v-model="page" :checked="checked"></next-step>
                <pre-step class="button" v-model="page"></pre-step>
                <reset class="button" v-model="checked" :page="page"></reset>
            </div>
        </div>
        <div v-else-if="page===3">
            <p>3.请介绍一下你自己:</p>
            <textarea v-model="text" placeholder="不少于100字"></textarea>
            <div class="bottom">
                <next-step class="button" v-model="page" :text="text" @submit="submit"></next-step>
                <pre-step class="button" v-model="page"></pre-step>
                <reset class="button" v-model="text" :page="page"></reset>
            </div>
        </div>
        <div v-else>
            <p>感谢您的填写!祝您生活愉快!</p>
        </div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script src="index.js"></script>
</body>

</html>

style.css

[v-cloak]{
    display: none;
}
body{
    background-color: rgb(241,241,241);
}
.page{
    position: absolute;
    width: 300px;
    height: 400px;
    background-color: white;
    top: 30%;
    left: 50%;
    margin-left: -200px;
    margin-top: -250px;
    padding: 30px 20px;
}
.bottom{
    width: 300px;
    position: absolute;
    bottom: 30px;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-around;
}
.button{
    background-color: rgb(49,194,230);
    border-radius: 5px;
    width: 120px;
    height: 40px;
    line-height: 40px;
    text-align: center;
    color: white;
    margin: 0 5px;
}
button{
    margin: 0px;
    padding: 0px;
    border: 0px;
    outline: none;
    position: relative;
    cursor: pointer;
}
button:active{
    top: 1px;
    left: 1px;
}
textarea{
    width: 100%;
    height: 100px;
}

index.js

Vue.component('next-step', {
    template: '<button @click="nextPage" :style="style" :disabled="disabled">{{title}}</button>',
    props: {
        value: {
            type: Number,
            default: 1
        },
        checked: {
            type: Array,
            default: function () {
                return [];
            }
        },
        text: {
            type: String,
            default: ""
        }
    },
    data: function () {
        return {
            currentPage: this.value,
            title: "下一步"
        }
    },
    computed: {
        style: function () {
            if ((this.currentPage == 2 && this.checked.length < 2) || (this.currentPage == 3 && this.text.length < 10)) {
                return {
                    backgroundColor: "rgb(222,225,230)"
                }
            }
        },
        disabled: function () {
            if (this.currentPage == 2 && this.checked.length < 2) {
                return true;
            }
            if (this.currentPage == 3 && this.text.length < 10) {
                return true;
            }
            return false;
        }
    },
    watch: {
        checked: function (val) {
            this.checked = val;
        },
        value: function (val) {
            var title = "";
            if (val == 1 || val == 2) {
                title = "下一步";
            } else {
                title = "提交";
            }
            this.currentPage = val;
            this.title = title;
        },
        text: function (val) {
            this.text = val;
        }
    },
    methods: {
        nextPage: function () {
            if (this.currentPage == 3) {
                this.$emit('submit');
            }
            this.currentPage++;
            this.$emit('input', this.currentPage);
        }
    }
})

Vue.component('pre-step', {
    template: '<button @click="prePage">上一步</button>',
    props: ['value'],
    data: function () {
        return {
            currentPage: this.value
        }
    },
    watch: {
        value: function (val) {
            this.currentPage = val;
        }
    },
    methods: {
        prePage: function () {
            this.currentPage--;
            this.$emit('input', this.currentPage);
        }
    }
})

Vue.component('reset', {
    template: '<button @click="reset">重置</button>',
    props: ['page', 'value'],
    methods: {
        reset: function () {
            if (this.page == 1) {
                this.$emit('input', "none");
            } else if (this.page == 2) {
                var checked = ['swim', 'movie'];
                this.$emit('input', checked);
            } else {
                this.$emit('input', "");
            }
        }
    }
})

var app = new Vue({
    el: '#app',
    data: {
        page: 1,
        picked: "none",
        checked: ['swim', 'movie'],
        text: ""
    },
    methods:{
        submit: function(){
            var sex="";
            if(this.picked=='male'){
                sex="男";
            }else if(this.picked=='female'){
                sex="女";
            }else{
                sex="保密";
            }
            var result={
                sex: sex,
                hobby: this.checked,
                description: this.text
            }
            console.log(result);
        }
    }
});

项目展示

Vue.js学习笔记—调查问卷WebAppVue.js学习笔记—调查问卷WebAppVue.js学习笔记—调查问卷WebAppVue.js学习笔记—调查问卷WebApp

项目总结

1.关于组件父组件向子组件传值:props属性,注意用v-model传值,组件使用value属性接收
2.使用watch监听每个组件相关数据的变化,并可以根据变化写出相应的业务逻辑
3.使用this.$emit()调用父组件相关函数,实现数据的双向绑定
4.使用computed计算属性,控制相关元素的样式设计
5.本程序不足:
①使用了三个组件next-step、pre-step、reset来实现三种按钮功能,有点冗余,可以将其合并为一个组件,根据接收的参数动态显示相关按钮及功能。
②html表单部分,使用大量重复代码,可以考虑将数据放入data中,利用v-for循环遍历渲染页面。