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

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

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

项目:调查问卷 WebApp

描述:

制作一个简单的调查问卷HTML5小应用,每页有一道题目,题目可以是单选题、多选题、填写题等,最终效果如下:在这里插入图片描述

说明

每一页可以通过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);
        }
    }
});

项目展示

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

项目总结

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

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值