第 6章 测测你是三国杀中的谁 ——调查测试类小程序 读者应该看过或玩过类似“你是金庸小说中的谁”“12星座性格测试”“东北话八级测试”等调查、测试类小游戏。这类游戏能带动用户的好奇心(我应该是金庸小说中的谁?),并激起用户的分享欲望(我是金庸小说中的风清扬,赶快发到朋友圈让朋友知道啊),从而成为一款长盛不衰的小游戏。 这类游戏的特点很明显: (1)有一系列调查问卷供用户回答,通常是选择一个选项或分数。 (2)根据用户的选择跳到下一题目(题目不一定连续)。 (3)最后显示答案,告诉用户的测试结果。 本章将介绍一个通用解决方案,所有题目和答案都以JSON格式存储。这样读者只需修改JSON文件的文案就能创建一个全新的测试类游戏。 关键知识点:form表单、图片、页面路由。 游戏界面如图6-1所示。 图6-1 6.1 数据结构 6.1.1 JSON介绍 JSON(JavaScript Object Notation)是一种轻量级数据交换格式,易于阅读和编写,同时也易于机器解析和生成。JSON基于JavaScript Programming Language、Standard ECMA-262 3rd Edition - December 1999的一个子集。JSON采用完全独立于语言的文本格式,也使用类似于C语言家族的习惯(包括C、C++、C#、Java、JavaScript、Perl、Python等)。这些特性使JSON成为理想的数据交换语言。 JSON建构于两种结构: ? “名称/值”对的集合(a collection of name/value pairs)在不同语言中被理解为对象(object)、纪录(record)、结构(struct)、字典(dictionary)、哈希表(hash table)、有键列表(keyed list)或关联数组 (associative array)。 ? 值的有序列表(An ordered list of values)在大部分语言中被理解为数组(array)。 这些都是常见的数据结构。事实上,大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间的交换成为可能。 JSON具有以下形式: 对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,以“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。例如: {'name': 'weixin developer'} 数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。 ['first', 'second'] 值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或数组(array)。这些结构可以嵌套。 6.1.2 问题和答案的数据结构 测试由问题和答案构成。用户通过回答一系列问题最终获得一个答案。 问题页面如图6-2所示。 图6-2 对应的数据结构如下: { "id": 1, "question": "比起循规蹈矩但有理可据的常规工作,你更喜欢去做些含有风险性但收益可观的创造性活动。", "answer": [ { "option": "A", "text": "是", "action": "2" }, { "option": "B", "text": "否", "action": "3" } ] } 问题的数据结构见表6-1。 表6-1 问题的数据结构 id 问题ID question 问题详情 answer 问题的选择项,为数组 option 问题选择项的标示 text 问题选择项的文本 action 问题选择项的动作 特别说明,每个问题有两个答案,你选择其中一个答案后,游戏会根据你的选项分配下一步的动作。action定义了两种动作: ? 跳转到第N题。例如,{"action": "2"}指的是选择该项后跳到第2题。 ? 跳转到答案。例如,{"action":"result_A"}指的是选择该项后显示第A种答案。 答案如图6-3所示。 图6-3 { "A": { "name": "吕蒙", "img": " ../../images/lvmeng.jpg", "text": "你是一个富有志向而又深谋远虑的人,喜欢为自己制定高瞻远瞩的长远目标,为实现最终的胜利甘愿选择隐忍的生活方式,不管过程有多艰辛多漫长你都甘之如饴。你享受生活带来的充实感,善于观察生活中的细节,做事会带有很明确的目的性。你用深藏不露诠释了一种最深邃的进取。" } } 结果的数据结构见表6-2。 表6-2 结果的数据结构 结果字段 字段说明 name 三国杀人物姓名 img 三国杀人物图片 text 三国杀人物性格解说 6.2 项目结构 完整代码可以查看下载资源的ch06/sgs。 项目结构如图6-4所示。 图6-4 项目有3个page:起始页、测试页、结果页。 项目的配置文件如下: 文件:app.json 1 { 2 "pages":[ 3 "pages/sgs/index", 4 "pages/sgs/show", 5 "pages/sgs/result" 6 ], 7 "window":{ 8 "backgroundTextStyle":"light", 9 "navigationBarBackgroundColor": "#fff", 10 "navigationBarTitleText": "测测你是三国杀里的谁", 11 "navigationBarTextStyle":"black" 12 } 13 } 6.2.1 起始页 起始页的界面如图6-1所示。程序的主体是显示三国杀封面图,并显示“开始测试”按钮。 参考程序:pages/sgs/index.wxml 1 2 3 测测你是三国杀里的谁 4 5 6 7 8 点击 “开始测试”按钮进入测试页面。 参考程序:pages/sgs/index.js 1 //index.js 2 //获取应用实例 3 var app = getApp() 4 Page({ 5 //事件处理函数 6 start: function() { 7 wx.navigateTo({ 8 url: '../sgs/show' 9 }) 10 } 11 }) 6.2.2 测试页 测试页的界面如图6-2所示。程序的主体是展示一系列题目供用户回答,并显示“下一题”按钮。 参考程序:pages/sgs/ show.wxml 1 2 3 {{answer.question}} 4
5 6 10 14 15 16
17
第4到16行定义一个form表单,内置两个单选框供用户选择。 第15行定义一个用于提交的button按钮,绑定到formSubmit方法。 用户点击“下一题”后,会根据JSON数据跳到下一题,或者进入结果页。 参考程序:pages/sgs/ show.js 1 //show.js 2 var sgsdata = require('../../utils/sgsdata.js') 3 //获取应用实例 4 var app = getApp() 5 Page({ 6 data: { 7 answers:{}, 8 answer:{}, 9 checked_0:false, 10 checked_1:false 11 }, 12 //表单提交事件处理函数 13 formSubmit: function(e) { 14 var nextId = e.detail.value.nextId; 15 if(nextId == ""){ 16 return; 17 } 18 if(nextId.indexOf('result') != -1){//result_N show result 19 var results = nextId.split('_'); 20 wx.navigateTo({ 21 url: '../sgs/result?id='+results[1] 22 }) 23 }else{ 24 this.setData({ 25 checked_0:false, 26 checked_1:false, 27 answer:this.data.answers[nextId] 28 29 }); 30 } 31 }, 32 onLoad: function () { 33 var ans = sgsdata.getAnswer(); 34 this.setData({ 35 answers:ans, 36 answer:ans[0] 37 }); 38 } 39 }) 6.2.3 结果页 结果页的界面如图6-3所示。程序的主体是展示答案,包括人物角色、图片、性格解读。 参考程序:pages/sgs/result.wxml 1 2 3 4 你是三国杀中的{{result.name}} 5 6 7 8 {{result.text}} 9 10 对应的js逻辑如下: 参考程序:pages/sgs/result.js 1 //result.js 2 var sgsdata = require('../../utils/sgsdata.js') 3 //获取应用实例 4 var app = getApp() 5 Page({ 6 data: { 7 result:{} 8 }, 9 onLoad: function (options) { 10 var id = options['id'] 11 var results = sgsdata.getResult(); 12 this.setData({ 13 result:results[id] 14 }); 15 } 16 }) 第10行,通过options获取上一个页面传递过来的参数。 对应的WXSS如下: 参考程序:pages/sgs/result.wxss 1 /**result.wxss**/ 2 .result_container { 3 height: 100%; 4 display: flex; 5 flex-direction: column; 6 align-items: center; 7 justify-content: space-between; 8 box-sizing: border-box; 9 } 10 11 .result_title{ 12 margin-bottom: 20rpx; 13 } 14 .result_content{ 15 margin-top: 10rpx; 16 padding: 10rpx; 17 border: 1px solid #F8F8FF; 18 } 第2行result_container定义测试结果的容器样式。 第11行result_title定义测试结果的标题样式。 第14行result_content定义测试结果的解读样式。 6.2.4 辅助JS utils/sgsdata.js用于保存问题和结果的json数据。根据小程序框架模块化的要求,我们提供两个对外接口: ? getAnswer提供所有问题数据。 ? getResult提供所有结果数据。 参考程序:utils/sgsdata.js 1 function getAnswer(){ 2 var data = [{"id":1,"question":"比起循规蹈矩但有理可据的常规工作,你更喜欢去做些含有风险性但收益可观的创造性活动。","answer":[{"option":"A","text":"是","action":"result_A"},{"option":"B","text":"否","action":"3"}]},............]; 3 return data; 4 } 5 6 function getResult(){ 7 var result = {"A":{"name":"吕蒙","img":"../../images/lvmeng.jpg","text":"你是一个富有志向而又深谋远虑的人,喜欢为自己制定高瞻远瞩的长远目标,为实现最终的胜利甘愿选择隐忍的生活方式,不管过程有多艰辛多漫长你都甘之如饴。你享受生活带来的充实感,善于观察生活中的细节,做事会带有很明确的目的性。你用深藏不露诠释了一种最深邃的进取。"}},............}; 8 return result; 9 } 10 11 module.exports = { 12 getAnswer: getAnswer, 13 getResult:getResult 14 } 6.3 小 结 本章通过编写“测测你是三国杀里的谁”项目向读者介绍了JSON的基本知识,包括如何在页面路由中传递数据、form表单的使用、如何使用图片。本章的项目是一个通用方案,读者可以自行修改问题和答案的逻辑和数据,创造新的调查测试游戏。