Vue.js学习笔记—调查问卷WebApp
程序员文章站
2022-05-18 17:16:44
...
参考《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循环遍历渲染页面。