生成問卷的部分參考微信小程序做問卷——前端部分(生成問卷)
實現效果
界面如下,分別展示了三種題型,單選題,多選題,簡答題。
單選只可以選擇一個,多選可以選擇多個,問答題寫在<textarea>
中,點擊完成會打印出整個表的數據。
比如下面是默認的數據
現在勾選單選和多選,以及改變回答部分再看一下數據
可以看到數據是匹配的,所以最後只要把生成好的數據提交到後端,那麼一份問卷就算是完成了。
實現
因爲是先寫的微信小程序做問卷——前端部分(生成問卷),所以重複的部分不再贅述了,建議先看生成問卷部分,回答問卷比生成問卷的邏輯簡單一些。
數據結構還是一樣的,先是生成問卷,然後再填寫生成好的問卷,所以兩者的數據結構是一致的。
questionnaireArray: [
{
"type": "SCQ",
"content": {
"description": "Which fruit do you like best?",
"options":
[
{ "id": 1, "name": "Lua", "isSelected": false },
{ "id": 2, "name": "Java", "isSelected": false },
{ "id": 3, "name": "C++", "isSelected": false }
]
}
},
{
"type": "MCQ",
"content": {
"description": "Which fruit do you like?",
"options":
[
{ "id": 1, "name": "OK", "isSelected": false },
{ "id": 2, "name": "Java", "isSelected": false },
{ "id": 3, "name": "C++", "isSelected": false }
]
}
},
{
"type": "SAQ",
"content": {
"description": "What's your name?",
"answer": "i dont know"
}
}
],
單選部分
<block wx:if="{{item.type === 'SCQ'}}">
<view class = 'SCQ' data-id='{{fatherIndex}}'>
<view class='SCQTitle'>
<view class='SCQQ'>Q</view>
<view class='SCQindex'>{{fatherIndex+1}}</view>
<view class='SCQquto'>:</view>
<text class='SCQDiscription' data-id='{{fatherIndex}}'>{{item.content.description}}</text>
</view>
<radio-group class="SCQOption" bindchange="radioChangeSCQ">
<label class="SCQText" wx:for="{{item.content.options}}" wx:key="SCQID" data-id='{{fatherIndex}}' bindtouchstart='getTempFatherIndex'>
<radio value="{{item.name}}" checked="{{item.isSelected}}"/>{{item.name}}
</label>
</radio-group>
</view>
</block>
用的結構還是和之前的一樣,不一樣的是用的<radio-group>
,在這個裏面申明<radio>
會自動生成單選按鈕,以及實現邏輯,即在衆多選項中只可以有一個處於被勾選的狀態。
但是他並不能改變js中的數據,所以還是要在radioChangeSCQ
裏面自己寫邏輯(這部分可能有API會直接得到,但是由於我是先寫生成部分,所以邏輯可以直接拿來用)
radioChangeSCQ:function(input){
var tempFatherIndex = this.data.currentFatherIndex;
var tempArray = this.data.questionnaireArray;
for (var i in tempArray[tempFatherIndex].content.options){
if (tempArray[tempFatherIndex].content.options[i].name == input.detail.value){
tempArray[tempFatherIndex].content.options[i].isSelected = true;
}
else{
tempArray[tempFatherIndex].content.options[i].isSelected = false;
}
}
this.setData({
questionnaireArray: tempArray,
});
},
其中input.detail.value
就是一個object
,比如上圖展示的第一題點擊Java
的時候,Java
被勾選,那麼該值就是Java
這部分主要是在頁面變更的時候,也可以改變js中的數據。首先拿到父節點的索引,再取得子節點的索引,然後再選項中遍歷一遍,所以選項是和自己點擊的input.detail.value
一致的話,就把數據的選擇改成選中狀態,那麼其他的選項都可以設置爲沒有被選中的狀態。
多選部分
<block wx:if="{{item.type === 'MCQ'}}">
<view class = 'MCQ' data-id='{{fatherIndex}}'>
<view class='MCQTitle'>
<view class='MCQQ'>Q</view>
<view class='MCQindex'>{{fatherIndex+1}}</view>
<view class='MCQquto'>:</view>
<text class='MCQDiscription' data-id='{{fatherIndex}}'>{{item.content.description}}</text>
</view>
<checkbox-group class="MCQOption" bindchange="checkboxChangeMCQ">
<label class="MCQText" wx:for="{{item.content.options}}" wx:key="MCQID" data-id='{{fatherIndex}}' bindtouchstart='getTempFatherIndex'>
<checkbox value="{{item.name}}" checked="{{item.isSelected}}" data-id='{{index}}'/>{{item.name}}
</label>
</checkbox-group>
</view>
</block>
這裏的input.detail.value
是多個值,比如第二題OK
和C++
,那麼該值是[OK,C++]
這是和單選有區別的地方
這裏用的是<checkbox-group>
,在裏面使用<checkbox>
屬性會自動生成多選界面以及邏輯,同樣數據的改變還是需要在checkboxChangeMCQ
中
checkboxChangeMCQ:function(input){
// console.log(input.detail.value);
var flag = false;
var tempFatherIndex = this.data.currentFatherIndex;
var tempArray = this.data.questionnaireArray;
for (var i in tempArray[tempFatherIndex].content.options) {
flag = false;
for(var j in input.detail.value){
if (tempArray[tempFatherIndex].content.options[i].name == input.detail.value[j]){
flag = true;
}
}
if(flag == true){
tempArray[tempFatherIndex].content.options[i].isSelected = true;
}
else{
tempArray[tempFatherIndex].content.options[i].isSelected = false;
}
}
this.setData({
questionnaireArray: tempArray,
});
},
這裏的邏輯就是對每個選項進行判斷,判斷是否處在被選中的選項之後,是就勾選,設置了flag
,是隻要滿足有一個相同就可以了。
問答部分
<block wx:if="{{item.type === 'SAQ'}}">
<view class = 'SAQ' data-id='{{fatherIndex}}'>
<view class='SAQTitle'>
<view class='SAQQ'>Q</view>
<view class='SAQindex'>{{fatherIndex+1}}</view>
<view class='SAQquto'>:</view>
<text class='SAQDiscription' data-id='{{fatherIndex}}'>{{item.content.description}}</text>
</view>
<textarea auto-height='true' class = "SAQAnswer" value='{{item.content.answer}}' bindblur='bindblurAnswerOfSAQ' data-id='{{fatherIndex}}'></textarea>
</view>
</block>
和生成問卷的時候一致,爲了完整性寫在這裏,但是不再解釋了。
bindblurAnswerOfSAQ: function (input) {
var tempIndex = input.currentTarget.dataset.id;
var tempArray = this.data.questionnaireArray;
tempArray[tempIndex].content.answer = input.detail.value;
// console.log(tempArray[tempIndex].content);
this.setData({
questionnaireArray: tempArray,
});
},
全部代碼
item.wxml
<view id="title">
<view class='titleContent'>問卷</view>
<image class='titlePriceIcon' src='{{priceIcon}}' mode='widthFix'></image>
<view class='priceContent'>25</view>
<view class='priceUnit'>元</view>
</view>
<view id = 'body' wx:for="{{questionnaireArray}}" wx:key="id" wx:for-index='fatherIndex'>
<block wx:if="{{item.type === 'SCQ'}}">
<view class = 'SCQ' data-id='{{fatherIndex}}'>
<view class='SCQTitle'>
<view class='SCQQ'>Q</view>
<view class='SCQindex'>{{fatherIndex+1}}</view>
<view class='SCQquto'>:</view>
<text class='SCQDiscription' data-id='{{fatherIndex}}'>{{item.content.description}}</text>
</view>
<radio-group class="SCQOption" bindchange="radioChangeSCQ">
<label class="SCQText" wx:for="{{item.content.options}}" wx:key="SCQID" data-id='{{fatherIndex}}' bindtouchstart='getTempFatherIndex'>
<radio value="{{item.name}}" checked="{{item.isSelected}}"/>{{item.name}}
</label>
</radio-group>
</view>
</block>
<block wx:if="{{item.type === 'MCQ'}}">
<view class = 'MCQ' data-id='{{fatherIndex}}'>
<view class='MCQTitle'>
<view class='MCQQ'>Q</view>
<view class='MCQindex'>{{fatherIndex+1}}</view>
<view class='MCQquto'>:</view>
<text class='MCQDiscription' data-id='{{fatherIndex}}'>{{item.content.description}}</text>
</view>
<checkbox-group class="MCQOption" bindchange="checkboxChangeMCQ">
<label class="MCQText" wx:for="{{item.content.options}}" wx:key="MCQID" data-id='{{fatherIndex}}' bindtouchstart='getTempFatherIndex'>
<checkbox value="{{item.name}}" checked="{{item.isSelected}}" data-id='{{index}}'/>{{item.name}}
</label>
</checkbox-group>
</view>
</block>
<block wx:if="{{item.type === 'SAQ'}}">
<view class = 'SAQ' data-id='{{fatherIndex}}'>
<view class='SAQTitle'>
<view class='SAQQ'>Q</view>
<view class='SAQindex'>{{fatherIndex+1}}</view>
<view class='SAQquto'>:</view>
<text class='SAQDiscription' data-id='{{fatherIndex}}'>{{item.content.description}}</text>
</view>
<textarea auto-height='true' class = "SAQAnswer" value='{{item.content.answer}}' bindblur='bindblurAnswerOfSAQ' data-id='{{fatherIndex}}'></textarea>
</view>
</block>
</view>
<button class="weui-btn" type="primary" bindtap='complete'>完成</button>
item.wxss
.arrow{
width: 10px;
height: 10px;
border-top: 2px solid #999;
border-right: 2px solid #999;
transform: rotate(-135deg);
margin-top:60rpx;
margin-left: 60rpx;
}
.backContent{
margin-top:40rpx;
margin-bottom: 20rpx;
}
#back{
display: flex;
flex-direction: row;
border: 2px solid #999;
}
#title{
display: flex;
flex-direction: row;
background-color: #E3E3E3;
padding: 30rpx;
}
.titlePriceIcon{
width: 60rpx;
position: absolute;
right: 120rpx;
}
.titleContent{
margin-left: 50rpx;
}
.priceContent{
position: absolute;
right: 70rpx;
}
.priceUnit{
position: absolute;
right: 20rpx;
}
.SCQselectIcon{
width: 60rpx;
}
.SCQOption{
display: flex;
flex-direction:column;
margin-top: 20rpx;
}
.MCQselectIcon{
width: 60rpx;
}
.SCQ{
padding: 20rpx;
border: 2rpx solid #999;
}
.SCQText{
margin-left: 20rpx;
/* color: #E3E3E3; */
/* border: 2rpx solid #999; */
width: 90%;
word-break: keep-all;
word-wrap: break-word;
}
.MCQ{
padding: 20rpx;
border: 2rpx solid #999;
}
.MCQText{
margin-left: 20rpx;
/* color: #E3E3E3; */
/* border: 2rpx solid #999; */
width: 90%;
word-break: keep-all;
word-wrap: break-word;
}
.SAQ{
padding: 20rpx;
border: 2rpx solid #999;
}
.SCQTitle{
display: flex;
flex-direction: row;
}
.MCQTitle{
display: flex;
flex-direction: row;
}
.SAQTitle{
display: flex;
flex-direction: row;
}
.MCQOption{
display: flex;
flex-direction: column;
margin-top: 20rpx;
}
.SAQAnswer{
border: 2px solid #999;
}
.SCQDiscription{
/* border: 2rpx solid #999; */
width: 90%;
word-break: keep-all;
word-wrap: break-word;
}
.MCQDiscription{
/* border: 2rpx solid #999; */
width: 90%;
word-break: keep-all;
word-wrap: break-word;
}
.SAQDiscription{
/* border: 2rpx solid #999; */
width: 90%;
word-break: keep-all;
word-wrap: break-word;
}
.SCQdeleteIcon{
width: 80rpx;
margin-left: 20rpx;
}
.MCQdeleteIcon{
width: 80rpx;
margin-left: 20rpx;
}
.SCQdeleteIcon1{
width: 60rpx;
margin-left: 20rpx;
}
.MCQdeleteIcon1{
width: 60rpx;
margin-left: 20rpx;
}
.SAQdeleteIcon{
width: 60rpx;
margin-left: 50rpx;
}
.SCQaddIcon1{
width:60rpx;
margin-left: 20rpx;
}
.MCQaddIcon1{
width:60rpx;
margin-left: 20rpx;
}
#body{
margin-top: 100rpx;
}
.weui-btn{
width: 50%;
margin-bottom: 20rpx;
}
item.js
// pages/yaoxh6/item/item.js
Page({
/**
* 頁面的初始數據
*/
data: {
priceIcon: "../../../images/price.png",
currentFatherIndex: 0,
questionnaireArray: [
{
"type": "SCQ",
"content": {
"description": "Which fruit do you like best?",
"options":
[
{ "id": 1, "name": "Lua", "isSelected": false },
{ "id": 2, "name": "Java", "isSelected": false },
{ "id": 3, "name": "C++", "isSelected": false }
]
}
},
{
"type": "MCQ",
"content": {
"description": "Which fruit do you like?",
"options":
[
{ "id": 1, "name": "OK", "isSelected": false },
{ "id": 2, "name": "Java", "isSelected": false },
{ "id": 3, "name": "C++", "isSelected": false }
]
}
},
{
"type": "SAQ",
"content": {
"description": "What's your name?",
"answer": "i dont know"
}
}
],
},
/**
* 生命週期函數--監聽頁面加載
*/
onLoad: function (options) {
console.log(options.id)
},
/**
* 生命週期函數--監聽頁面初次渲染完成
*/
onReady: function () {
},
/**
* 生命週期函數--監聽頁面顯示
*/
onShow: function () {
},
/**
* 生命週期函數--監聽頁面隱藏
*/
onHide: function () {
},
/**
* 生命週期函數--監聽頁面卸載
*/
onUnload: function () {
},
/**
* 頁面相關事件處理函數--監聽用戶下拉動作
*/
onPullDownRefresh: function () {
},
/**
* 頁面上拉觸底事件的處理函數
*/
onReachBottom: function () {
},
/**
* 用戶點擊右上角分享
*/
onShareAppMessage: function () {
},
// fun : function(){
// var q = {
// test: this.data.test,
// test2: this.data.test2
// }
// wx.cloud.callFunction({
// name: 'release_questionnaire',
// data: {
// content: JSON.stringify(q)
// },
// success: res => {
// // test = JSON.stringify(res)
// // this.setData({
// // test : JSON.stringify(res.result.results.data[0].description)
// // })
// console.log('success')
// }
// })
// },
// fun2 : function(){
// wx.cloud.callFunction({
// name: 'get_all_questionnaire',
// success: res => {
// console.log(res)
// var last = res.result.results.data[8].content
// this.setData({
// test: JSON.parse(last).test
// })
// console.log('success')
// }
// })
// }
goBack : function(){
console.log('to task page')
wx.switchTab({
url: '../task/task',
})
},
getTempFatherIndex: function (input) {
var tempFatherIndex = input.currentTarget.dataset.id;
//console.log('currentFatherIndex: ' + tempFatherIndex);
this.setData({
currentFatherIndex: tempFatherIndex,
});
},
radioChangeSCQ:function(input){
var tempFatherIndex = this.data.currentFatherIndex;
var tempArray = this.data.questionnaireArray;
for (var i in tempArray[tempFatherIndex].content.options){
if (tempArray[tempFatherIndex].content.options[i].name == input.detail.value){
tempArray[tempFatherIndex].content.options[i].isSelected = true;
}
else{
tempArray[tempFatherIndex].content.options[i].isSelected = false;
}
}
this.setData({
questionnaireArray: tempArray,
});
},
checkboxChangeMCQ:function(input){
// console.log(input.detail.value);
var flag = false;
var tempFatherIndex = this.data.currentFatherIndex;
var tempArray = this.data.questionnaireArray;
for (var i in tempArray[tempFatherIndex].content.options) {
flag = false;
for(var j in input.detail.value){
if (tempArray[tempFatherIndex].content.options[i].name == input.detail.value[j]){
flag = true;
}
}
if(flag == true){
tempArray[tempFatherIndex].content.options[i].isSelected = true;
}
else{
tempArray[tempFatherIndex].content.options[i].isSelected = false;
}
}
this.setData({
questionnaireArray: tempArray,
});
},
bindblurAnswerOfSAQ: function (input) {
var tempIndex = input.currentTarget.dataset.id;
var tempArray = this.data.questionnaireArray;
tempArray[tempIndex].content.answer = input.detail.value;
// console.log(tempArray[tempIndex].content);
this.setData({
questionnaireArray: tempArray,
});
},
complete :function(){
console.log(this.data.questionnaireArray);
},
})