MBTI 性格测试小程序实战

打印 上一主题 下一主题

主题 1002|帖子 1002|积分 3006

MBTI 性格测试应用介绍

参考项目:16Personalities(https://www.16personalities.com/ch)





MBTI 实现方案介绍

核心构成:


  • 题目
  • 用户答案
  • 评分规则
题目布局

暂时使用JSON,便于明确,result代表题目对应的结果
  1. [
  2.     {
  3.         "title": "你通常更喜欢",
  4.         "options": [
  5.             {
  6.                 "result": "I",
  7.                 "value": "独自工作",
  8.                 "key": "A"
  9.             },
  10.             {
  11.                 "result": "E",
  12.                 "value": "与他人合作",
  13.                 "key": "B"
  14.             }
  15.         ]
  16.     }
  17. ]
复制代码
优点:灵活、容易排序
相比于用选项作为key,布局更清楚,更易于明确和扩展前后端都可声明类型;缺点是占用空间(可以进行预处理)
  1. {
  2.     "title": "题目",
  3.     "a": "结果1",
  4.     "b": "结果2",
  5.     "c": "结果3"
  6. }
复制代码

用户答案布局

用户提交答案的时间,进需要通报一个数组,数组内是选项:["A","B"],按数组顺序匹配对应的题目。
优点:相较于直接将答案放到题目当中一起提交,数组不用再完备的通报题目布局,节省传输体积,进步性能。
  1. ["A","A","A","B","A","A","A","B","B","A"]
复制代码

评分规则


MBTI 评分原理

迈尔斯-布里格斯性格分类法
   迈尔斯-布里格斯类型指标(英语:Myers-Briggs Type Indicator,简称MBTI,或译麦布二氏生理类型量表)是一种品德类型的评量工具,由荣格的类型理论发展而来,它表明人们天生在感知和决策的方式上存在差别生理偏好。其理论中最浅显的部分是四组相反的先天偏好:内向与外向(Introversion-Extraversion)、实感与直觉(Sensing-iNtuition)、思索与情感(Thinking-Feeling)、判定与感知(Judging-Perceiving),四项偏好可构成16种稳固的品德类型。该指标旨在让健康个体明确自己和彼此的认知与决策倾向,并不反映本领或风致。
MBTI是由两名美国人——凯瑟琳·库克·布里格斯和她的女儿伊莎贝尔·布里格斯·迈尔斯所建构,最早于1944年发表。
    MBTI将生理差异分类为4个对立的组合(或称“二分法”),一个人在每个组合中各拥有1个偏好:
  

  • 内向与外向(I/E)
  • 实感与直觉(S/N)
  • 思索与情感(T/F)
  • 判定与感知(J/P)
  四个字母的组合依照E/I、S/N、T/F、J/P的顺序,由此产生了16种可能的字母组合,如ESTJ、ISFP、INFJ、ENTP等16种独特的类型。在MBTI的理论中,“类型”表达的讯息量不只是“4个偏好”,它代表了功能(S、N、T、F)、能量态度(E、I)以及对外界的态度(J、P)之间的一组复杂的动态关系。

每道题目都是四个组合的此中之一设定,为了判定找个人属于组合里的哪个偏好。
如,为了判定是I人照旧E人(result字段):
  1. [
  2.     {
  3.         "title": "你通常更喜欢",
  4.         "options": [
  5.             {
  6.                 "result": "I",
  7.                 "value": "独自工作",
  8.                 "key": "A"
  9.             },
  10.             {
  11.                 "result": "E",
  12.                 "value": "与他人合作",
  13.                 "key": "B"
  14.             }
  15.         ]
  16.     }
  17. ]
复制代码
按照这个思路,可以统计题目中所有的偏好,比如答完题目,统计一共选了10个I,2个E,很容易判定答题者是I人,同理可判定其他型品德。
所以出题的时间,给每个选项的答案对应设置一个属性。如:


  • 第一题A对应I,B对应E
  • 第二题A对应E,B对应I
  • 第三题A对应S,B对应N
  • 第四题A对应T,B对应F
  • 第五题A对应P,B对应J
如果用户选择了[A,B,A,A,A],两个I,一个S,一个T,一个P,很明显是ISTP品德。

评分结果计算原理


  • 创建一个评分结果集,预先创建包括MBTI的所有16中角色(品德)

题目评分结果对应的json布局:
  1. [
  2.   {
  3.     "resultProp": [
  4.       "I",
  5.       "S",
  6.       "T",
  7.       "J"
  8.     ],
  9.     "resultDesc": "忠诚可靠,被公认为务实,注重细节。",
  10.     "resultPicture": "icon_url_istj",
  11.     "resultName": "ISTJ(物流师)"
  12.   },
  13.   {
  14.     "resultProp": [
  15.       "I",
  16.       "S",
  17.       "F",
  18.       "J"
  19.     ],
  20.     "resultDesc": "善良贴心,以同情心和责任为特点。",
  21.     "resultPicture": "icon_url_isfj",
  22.     "resultName": "ISFJ(守护者)"
  23.   }
  24. ]
复制代码

  • 怎样计算结果
每个结果有一个resultProp字段,是一个元素不重复的数组(属性聚集),里面的内容和题目选项的result字段匹配。
  1. [
  2.     {
  3.         "title": "你通常更喜欢",
  4.         "options": [
  5.             {
  6.                 "result": "I",
  7.                 "value": "独自工作",
  8.                 "key": "A"
  9.             },
  10.             {
  11.                 "result": "E",
  12.                 "value": "与他人合作",
  13.                 "key": "B"
  14.             }
  15.         ]
  16.     }
  17. ]
复制代码
如果用户第一题选了A,对应的属性如果是I,那么遍历这16种结果,然后判定角色对应的resultProp里面是否包含I,包含则对应角色就 +1 分,不包含不得分。
最终遍历完所有题目后,可以得出16种结果中,哪个角色得分最高,即最终的评分结果。

MBTI 小程序 Demo 数据


题目列表

每个选项包含了对应的结果,questions.json:
  1. [
  2.     {
  3.         "options": [
  4.             {
  5.                 "result": "I",
  6.                 "value": "独自工作",
  7.                 "key": "A"
  8.             },
  9.             {
  10.                 "result": "E",
  11.                 "value": "与他人合作",
  12.                 "key": "B"
  13.             }
  14.         ],
  15.         "title": "你通常更喜欢"
  16.     },
  17.     {
  18.         "options": [
  19.             {
  20.                 "result": "J",
  21.                 "value": "喜欢有明确的计划",
  22.                 "key": "A"
  23.             },
  24.             {
  25.                 "result": "P",
  26.                 "value": "更愿意随机应变",
  27.                 "key": "B"
  28.             }
  29.         ],
  30.         "title": "当安排活动时"
  31.     },
  32.     {
  33.         "options": [
  34.             {
  35.                 "result": "T",
  36.                 "value": "认为应该严格遵守",
  37.                 "key": "A"
  38.             },
  39.             {
  40.                 "result": "F",
  41.                 "value": "认为应灵活运用",
  42.                 "key": "B"
  43.             }
  44.         ],
  45.         "title": "你如何看待规则"
  46.     },
  47.     {
  48.         "options": [
  49.             {
  50.                 "result": "E",
  51.                 "value": "经常是说话的人",
  52.                 "key": "A"
  53.             },
  54.             {
  55.                 "result": "I",
  56.                 "value": "更倾向于倾听",
  57.                 "key": "B"
  58.             }
  59.         ],
  60.         "title": "在社交场合中"
  61.     },
  62.     {
  63.         "options": [
  64.             {
  65.                 "result": "J",
  66.                 "value": "先研究再行动",
  67.                 "key": "A"
  68.             },
  69.             {
  70.                 "result": "P",
  71.                 "value": "边做边学习",
  72.                 "key": "B"
  73.             }
  74.         ],
  75.         "title": "面对新的挑战"
  76.     },
  77.     {
  78.         "options": [
  79.             {
  80.                 "result": "S",
  81.                 "value": "注重细节和事实",
  82.                 "key": "A"
  83.             },
  84.             {
  85.                 "result": "N",
  86.                 "value": "注重概念和想象",
  87.                 "key": "B"
  88.             }
  89.         ],
  90.         "title": "在日常生活中"
  91.     },
  92.     {
  93.         "options": [
  94.             {
  95.                 "result": "T",
  96.                 "value": "更多基于逻辑分析",
  97.                 "key": "A"
  98.             },
  99.             {
  100.                 "result": "F",
  101.                 "value": "更多基于个人情感",
  102.                 "key": "B"
  103.             }
  104.         ],
  105.         "title": "做决定时"
  106.     },
  107.     {
  108.         "options": [
  109.             {
  110.                 "result": "S",
  111.                 "value": "喜欢有结构和常规",
  112.                 "key": "A"
  113.             },
  114.             {
  115.                 "result": "N",
  116.                 "value": "喜欢自由和灵活性",
  117.                 "key": "B"
  118.             }
  119.         ],
  120.         "title": "对于日常安排"
  121.     },
  122.     {
  123.         "options": [
  124.             {
  125.                 "result": "P",
  126.                 "value": "首先考虑可能性",
  127.                 "key": "A"
  128.             },
  129.             {
  130.                 "result": "J",
  131.                 "value": "首先考虑后果",
  132.                 "key": "B"
  133.             }
  134.         ],
  135.         "title": "当遇到问题时"
  136.     },
  137.     {
  138.         "options": [
  139.             {
  140.                 "result": "T",
  141.                 "value": "时间是一种宝贵的资源",
  142.                 "key": "A"
  143.             },
  144.             {
  145.                 "result": "F",
  146.                 "value": "时间是相对灵活的概念",
  147.                 "key": "B"
  148.             }
  149.         ],
  150.         "title": "你如何看待时间"
  151.     }
  152. ]
复制代码

题目结果表

question_results.json
  1. [
  2.   {
  3.     "resultProp": [
  4.       "I",
  5.       "S",
  6.       "T",
  7.       "J"
  8.     ],
  9.     "resultDesc": "忠诚可靠,被公认为务实,注重细节。",
  10.     "resultPicture": "icon_url_istj",
  11.     "resultName": "ISTJ(物流师)"
  12.   },
  13.   {
  14.     "resultProp": [
  15.       "I",
  16.       "S",
  17.       "F",
  18.       "J"
  19.     ],
  20.     "resultDesc": "善良贴心,以同情心和责任为特点。",
  21.     "resultPicture": "icon_url_isfj",
  22.     "resultName": "ISFJ(守护者)"
  23.   },
  24.   {
  25.     "resultProp": [
  26.       "I",
  27.       "N",
  28.       "F",
  29.       "J"
  30.     ],
  31.     "resultDesc": "理想主义者,有着深刻的洞察力,善于理解他人。",
  32.     "resultPicture": "icon_url_infj",
  33.     "resultName": "INFJ(占有者)"
  34.   },
  35.   {
  36.     "resultProp": [
  37.       "I",
  38.       "N",
  39.       "T",
  40.       "J"
  41.     ],
  42.     "resultDesc": "独立思考者,善于规划和实现目标,理性而果断。",
  43.     "resultPicture": "icon_url_intj",
  44.     "resultName": "INTJ(设计师)"
  45.   },
  46.   {
  47.     "resultProp": [
  48.       "I",
  49.       "S",
  50.       "T",
  51.       "P"
  52.     ],
  53.     "resultDesc": "冷静自持,善于解决问题,擅长实践技能。",
  54.     "resultPicture": "icon_url_istp",
  55.     "resultName": "ISTP(运动员)"
  56.   },
  57.   {
  58.     "resultProp": [
  59.       "I",
  60.       "S",
  61.       "F",
  62.       "P"
  63.     ],
  64.     "resultDesc": "具有艺术感和敏感性,珍视个人空间和自由。",
  65.     "resultPicture": "icon_url_isfp",
  66.     "resultName": "ISFP(艺术家)"
  67.   },
  68.   {
  69.     "resultProp": [
  70.       "I",
  71.       "N",
  72.       "F",
  73.       "P"
  74.     ],
  75.     "resultDesc": "理想主义者,富有创造力,以同情心和理解他人著称。",
  76.     "resultPicture": "icon_url_infp",
  77.     "resultName": "INFP(治愈者)"
  78.   },
  79.   {
  80.     "resultProp": [
  81.       "I",
  82.       "N",
  83.       "T",
  84.       "P"
  85.     ],
  86.     "resultDesc": "思维清晰,探索精神,独立思考且理性。",
  87.     "resultPicture": "icon_url_intp",
  88.     "resultName": "INTP(学者)"
  89.   },
  90.   {
  91.     "resultProp": [
  92.       "E",
  93.       "S",
  94.       "T",
  95.       "P"
  96.     ],
  97.     "resultDesc": "敢于冒险,乐于冒险,思维敏捷,行动果断。",
  98.     "resultPicture": "icon_url_estp",
  99.     "resultName": "ESTP(拓荒者)"
  100.   },
  101.   {
  102.     "resultProp": [
  103.       "E",
  104.       "S",
  105.       "F",
  106.       "P"
  107.     ],
  108.     "resultDesc": "热情开朗,善于社交,热爱生活,乐于助人。",
  109.     "resultPicture": "icon_url_esfp",
  110.     "resultName": "ESFP(表演者)"
  111.   },
  112.   {
  113.     "resultProp": [
  114.       "E",
  115.       "N",
  116.       "F",
  117.       "P"
  118.     ],
  119.     "resultDesc": "富有想象力,充满热情,善于激发他人的活力和潜力。",
  120.     "resultPicture": "icon_url_enfp",
  121.     "resultName": "ENFP(倡导者)"
  122.   },
  123.   {
  124.     "resultProp": [
  125.       "E",
  126.       "N",
  127.       "T",
  128.       "P"
  129.     ],
  130.     "resultDesc": "充满创造力,善于辩论,挑战传统,喜欢探索新领域。",
  131.     "resultPicture": "icon_url_entp",
  132.     "resultName": "ENTP(发明家)"
  133.   },
  134.   {
  135.     "resultProp": [
  136.       "E",
  137.       "S",
  138.       "T",
  139.       "J"
  140.     ],
  141.     "resultDesc": "务实果断,善于组织和管理,重视效率和目标。",
  142.     "resultPicture": "icon_url_estj",
  143.     "resultName": "ESTJ(主管)"
  144.   },
  145.   {
  146.     "resultProp": [
  147.       "E",
  148.       "S",
  149.       "F",
  150.       "J"
  151.     ],
  152.     "resultDesc": "友善热心,以协调、耐心和关怀为特点,善于团队合作。",
  153.     "resultPicture": "icon_url_esfj",
  154.     "resultName": "ESFJ(尽责者)"
  155.   },
  156.   {
  157.     "resultProp": [
  158.       "E",
  159.       "N",
  160.       "F",
  161.       "J"
  162.     ],
  163.     "resultDesc": "热情关爱,善于帮助他人,具有领导力和社交能力。",
  164.     "resultPicture": "icon_url_enfj",
  165.     "resultName": "ENFJ(教导着)"
  166.   },
  167.   {
  168.     "resultProp": [
  169.       "E",
  170.       "N",
  171.       "T",
  172.       "J"
  173.     ],
  174.     "resultDesc": "果断自信,具有领导才能,善于规划和执行目标。",
  175.     "resultPicture": "icon_url_entj",
  176.     "resultName": "ENTJ(统帅)"
  177.   }
  178. ]
复制代码

其他资源

主页背景图片等资源,可以借助AI生成

Taro跨端小程序入门


为什么开发小程序?



  • 基于微信生态,易于流传分享
  • 不用下载,直接打开使用即可
小程序开发和网页开发基本一致,都具有在线热更新、调试、版本兼容、打包上线。
小程序开发的真正痛点:可能有一些权限或者功能必须要企业号。

技能选型



  • Taro
  • Taro UI组件库
  • React
  • TypeScript
Taro官方文档:https://taro-docs.jd.com/docs/
做项目建议选用一个组件库,提升开发效率!
推荐使用与Taro官方框架兼容的组件库,否则容易出现跨端后样式丢失的题目。


  • taro-ui:https://taro-ui.jd.com/#/(推荐)
  • nut-ui
开发准备

微信开发者工具:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

入门指南


项目初始化

官方文档:https://taro-docs.jd.com/docs/GETTING-STARTED
Taro版本:这里选择3.x
node.js版本:>=16.20(我用的18.18.0)
npm版本:>=8(我用的9.8.1)
1)安装
  1. # 使用 npm 安装 CLI
  2. $ npm install -g @tarojs/cli
  3. # OR 使用 yarn 安装 CLI
  4. $ yarn global add @tarojs/cli
  5. # OR 安装了 cnpm,使用 cnpm 安装 CLI
  6. $ cnpm install -g @tarojs/cli
复制代码
这样会默认安装最新的版本,我们可以指定版本安装(如果安装了最新版本,直接再次安装指定版本即可):
  1. npm install -g @tarojs/cli@3.6.28
复制代码
使用taro -v检察版本信息:

2)新建目录question-craft,初始化git项目

3)执行下令,初始化小程序项目
  1. taro init mbti-test-mini
复制代码


项目运行

使用WebStorm打开项目,进入终端执行npm install,发现依赖下载失败:
  1. PS E:\E\IDEAWorkSpace\question-craft\mbti-test-mini> npm install
  2. npm ERR! code ERESOLVE
  3. npm ERR! ERESOLVE unable to resolve dependency tree
  4. npm ERR!                                          
  5. npm ERR! While resolving: mbti-test-mini@1.0.0     
  6. npm ERR! Found: react@18.2.0                       
  7. npm ERR! node_modules/react
  8. npm ERR!   react@"^18.0.0" from the root project
  9. npm ERR!   peer react@">=16.13.0" from taro-ui@3.3.0
  10. npm ERR!   node_modules/taro-ui
  11. npm ERR!     taro-ui@"^3.2.1" from the root project
  12. npm ERR!   2 more (@tarojs/taro-rn, react-native)
  13. npm ERR!
  14. npm ERR! Could not resolve dependency:
  15. npm ERR! peer react@"^18.3.1" from react-dom@18.3.1
  16. npm ERR! node_modules/react-dom
  17. npm ERR!   react-dom@"^18.0.0" from the root project
  18. npm ERR!   peer react-dom@">=16.13.0" from taro-ui@3.3.0
  19. npm ERR!   node_modules/taro-ui
  20. npm ERR!     taro-ui@"^3.2.1" from the root project
  21. npm ERR!
  22. npm ERR! Fix the upstream dependency conflict, or retry
  23. npm ERR! this command with --force or --legacy-peer-deps
  24. npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
  25. npm ERR!
  26. npm ERR!
  27. npm ERR! For a full report see:
  28. npm ERR! C:\Users\ada\AppData\Local\npm-cache\_logs\2024-08-10T03_43_08_487Z-eresolve-report.txt
  29. npm ERR! A complete log of this run can be found in: C:\Users\ada\AppData\Local\npm-cache\_logs\2024-08-10T03_43_08_487Z-debug-0.log
  30. PS E:\E\IDEAWorkSpace\question-craft\mbti-test-mini>
复制代码
可以查阅资料,或者问问AI,执行npm install --force,强制安装成功(不要使用邪术上网)
执行npm run dev:weapp,或者打开package.json文件,点击对应脚本运行:

dev:weapp:开发测试使用,即时编译,自动更新
build:weapp:打包上线使用,体积更小
运行之后使用微信开发者工具打开项目:



设置开发规范



  • eslint:代码规范
  • prettier:代码美化(格式)


eslint补充设置,关闭双引号校验:
  1. {
  2.   "extends": ["taro/react"],
  3.   "rules": {
  4.     "react/jsx-uses-react": "off",
  5.     "react/react-in-jsx-scope": "off",
  6.     "jsx-quotes": "off"
  7.   }
  8. }
复制代码


测试组件引入

官网文档:https://taro-ui.jd.com/#/docs/quickstart
在src/app.ts中全局引入taro-ui:
  1. import 'taro-ui/dist/style/index.scss' // 引入组件样式 - 方式一
复制代码
随便找个组件复制进项目进行测试,检察是否成功引入。

开发示例页面


  • 在全局设置文件src/app.config.ts,新增页面路由
  • 复制已有页面,创建新页面
  • 根据自己的需要,复制组件,拼出完备页面
  • 按照需求,定制开发
  • 页面跳转
MBTI 跨端小程序实战


全局规范和设置

依照函数式组件写法:
  1. export default () => {
  2.   return (
  3.     <View className="index">
  4.       <Text>Hello world!</Text>
  5.     </View>
  6.   );
  7. };
复制代码
修改应用标题src/app.config.ts:
  1. export default defineAppConfig({
  2.   pages: [
  3.     'pages/index/index'
  4.   ],
  5.   window: {
  6.     backgroundTextStyle: 'light',
  7.     navigationBarBackgroundColor: '#fff',
  8.     navigationBarTitleText: 'MBTI 性格测试',
  9.     navigationBarTextStyle: 'black'
  10.   }
  11. })
复制代码
再将src/pages/index/index.config.ts下的标题注释掉:
相当于每个页面可以有自己的标题,在对应页面的.config.ts中声明即可,这里我们直接注释掉
  1. export default definePageConfig({
  2.   // navigationBarTitleText: '首页'
  3. })
复制代码


主页


结果图



主页src/pages/index/index.tsx

  1. import { View, Image } from "@tarojs/components";
  2. import { AtButton } from "taro-ui";
  3. import headerBg from "../../assets/headerBg.png";
  4. import "./index.scss";
  5. import GlobalFooter from "../../components/GlobalFooter";
  6. /**
  7. * 主页
  8. */
  9. export default () => {
  10.   return (
  11.     <View className="indexPage">
  12.       <View className="at-article__h1 title">MBTI 性格测试</View>
  13.       <View className="at-article__h2 subTitle">只需2分钟,就能“惊人般准确”地描述出你是谁,以及你为何以这样的方式行事。</View>
  14.       <AtButton type="primary" circle className="enterBtn">
  15.         开始测试
  16.       </AtButton>
  17.       <Image className="headerBg" src={headerBg} />
  18.       <GlobalFooter />
  19.     </View>
  20.   );
  21. };
复制代码

主页样式src/pages/index/index.scss

  1. .indexPage {
  2.   background: #5DBFD8;
  3.   .title {
  4.     color: white;
  5.     padding-top: 48px;
  6.     text-align: center;
  7.   }
  8.   .subTitle {
  9.     color: white;
  10.     margin-top: 48px;
  11.   }
  12.   .enterBtn {
  13.     margin-top: 150px;
  14.     width: 60vw;
  15.   }
  16.   .headerBg {
  17.     margin-top: 100px;
  18.     height: 300px;
  19.   }
  20. }
复制代码

全局底部栏组件src/components/GlobalFooter/index.tsx

  1. import { View } from "@tarojs/components";
  2. import "./index.scss";
  3. /**
  4. * 全局底部栏组件
  5. */
  6. export default () => {
  7.   return <View className="globalFooter">作者:十六</View>;
  8. };
复制代码

全局底部栏组件样式src/components/GlobalFooter/index.scss

  1. .globalFooter {
  2.   position: fixed;
  3.   bottom: 16px;
  4.   left: 0;
  5.   right: 0;
  6.   text-align: center;
  7. }
复制代码

全局统一样式src/app.scss

  1. .at-button--primary {
  2.   background-color: dodgerblue;
  3.   boilder-color: dodgerblue;
  4. }
复制代码

答题页面


结果图


开发步骤:

  • 先写组件HTML(Radio组件)
  • 再调解样式
  • 最后写逻辑(上一题、下一题)
页面src/pages/doQuestion/index.tsx

  1. import { View, Image } from "@tarojs/components";
  2. import { AtButton } from "taro-ui";
  3. import headerBg from "../../assets/headerBg.png";
  4. import "./index.scss";
  5. import questionResults from "../../data/question_results.json";
  6. import GlobalFooter from "../../components/GlobalFooter";
  7. import Taro from "@tarojs/taro";
  8. /**
  9. * 测试结果页面
  10. */
  11. export default () => {
  12.   const result = questionResults[0];
  13.   return (
  14.     <View className="resultPage">
  15.       <View className="at-article__h1 title">{result.resultName}</View>
  16.       <View className="at-article__h2 subTitle">{result.resultDesc}</View>
  17.       <AtButton type="primary" circle className="enterBtn" onClick={() => {
  18.         // 关闭所有页面,打开到应用内的某个页面
  19.         Taro.reLaunch({
  20.           url: '/pages/index/index'
  21.         })
  22.       }}
  23.       >
  24.         返回主页
  25.       </AtButton>
  26.       <Image className="headerBg" src={headerBg} />
  27.       <GlobalFooter />
  28.     </View>
  29.   );
  30. };
复制代码

样式src/pages/doQuestion/index.scss

  1. .doQuestionPage {
  2.   .title {
  3.     margin-bottom: 48px;
  4.   }
  5.   .options-wrapper {
  6.     margin-bottom: 48px;
  7.   }
  8.   .controlBtn {
  9.     margin: 24px 48px;
  10.   }
  11. }
复制代码

结果页面


结果图



页面src/pages/result/index.tsx

使用Taro.reLaunch关闭所有页面,打开到应用内的某个页面,防止页面无限叠加
  1. import { View, Image } from "@tarojs/components";
  2. import { AtButton } from "taro-ui";
  3. import headerBg from "../../assets/headerBg.png";
  4. import "./index.scss";
  5. import questionResults from "../../data/question_results.json";
  6. import GlobalFooter from "../../components/GlobalFooter";
  7. import Taro from "@tarojs/taro";
  8. /**
  9. * 测试结果页面
  10. */
  11. export default () => {
  12.   const result = questionResults[0];
  13.   return (
  14.     <View className="resultPage">
  15.       <View className="at-article__h1 title">{result.resultName}</View>
  16.       <View className="at-article__h2 subTitle">{result.resultDesc}</View>
  17.       <AtButton type="primary" circle className="enterBtn" onClick={() => {
  18.         // 关闭所有页面,打开到应用内的某个页面
  19.         Taro.reLaunch({
  20.           url: '/pages/index/index'
  21.         })
  22.       }}
  23.       >
  24.         返回主页
  25.       </AtButton>
  26.       <Image className="headerBg" src={headerBg} />
  27.       <GlobalFooter />
  28.     </View>
  29.   );
  30. };
复制代码

样式src/pages/result/index.scss

  1. .resultPage {
  2.   background: #5DBFD8;
  3.   .title {
  4.     color: white;
  5.     padding-top: 48px;
  6.     text-align: center;
  7.   }
  8.   .subTitle {
  9.     color: white;
  10.     margin-top: 48px;
  11.   }
  12.   .enterBtn {
  13.     margin-top: 150px;
  14.     width: 60vw;
  15.   }
  16.   .headerBg {
  17.     margin-top: 100px;
  18.     height: 300px;
  19.   }
  20. }
复制代码

页面设置src/pages/result/index.config.ts

设置页面标题
  1. export default definePageConfig({
  2.   navigationBarTitleText: '查看结果', // 设置页面标题
  3. })
复制代码

路由设置src/app.config.ts

  1. export default defineAppConfig({
  2.   pages: [
  3.     'pages/index/index',
  4.     'pages/doQuestion/index',
  5.     'pages/result/index'
  6.   ],
  7.   window: {
  8.     backgroundTextStyle: 'light',
  9.     navigationBarBackgroundColor: '#fff',
  10.     navigationBarTitleText: 'MBTI 性格测试',
  11.     navigationBarTextStyle: 'black'
  12.   }
  13. })
复制代码

评分模块


CodeGeex生成对应评分算法代码

AI Prompt
请根据我下面的题目评分算法原理,帮我用 js 获取到得分最高的题目评分结果,要求算法清楚易懂,性能要求高,多补充一些注释。
用户提交的答案 answerList: [“A”]
题目列表 questions:
  1. [
  2.     {
  3.         "title": "你通常更喜欢",
  4.         "options": [
  5.             {
  6.                 "result": "I",
  7.                 "value": "独自工作",
  8.                 "key": "A"
  9.             },
  10.             {
  11.                 "result": "E",
  12.                 "value": "与他人合作",
  13.                 "key": "B"
  14.             }
  15.         ]
  16.     }
  17. ]
复制代码
题目评分结果 question_results:
  1. [
  2.   {
  3.     "resultProp": [
  4.       "I",
  5.       "S",
  6.       "T",
  7.       "J"
  8.     ],
  9.     "resultDesc": "忠诚可靠,被公认为务实,注重细节。",
  10.     "resultPicture": "icon_url_istj",
  11.     "resultName": "ISTJ(物流师)"
  12.   },
  13. ]
复制代码
评分原理:答案数组的每个元素和题目数组中每个元素的某个选项的key对应,从而获取到对应的 result 属性;题目评分结果的 resultProp 聚会合如果包含该属性,就+1分,最后计算哪个评分结果(question_result)分数最高。
AI 结果
这个函数起首遍历题目列表和答案列表,统计每个选项的计数。然后遍历评分结果列表,计算每个评分结果的分数,最后返回最高分数和最高分数对应的评分结果。
  1. function getMaxScore(answerList, questions, question_results) {
  2.   // 初始化一个对象,用于存储每个选项的计数
  3.   const optionCount = {};
  4.   // 遍历题目列表
  5.   for (const question of questions) {
  6.     // 遍历答案列表
  7.     for (const answer of answerList) {
  8.       // 遍历题目中的选项
  9.       for (const option of question.options) {
  10.         // 如果答案和选项的key匹配
  11.         if (option.key === answer) {
  12.           // 获取选项的result属性
  13.           const result = option.result;
  14.           // 如果result属性不在optionCount中,初始化为0
  15.           if (!optionCount[result]) {
  16.             optionCount[result] = 0;
  17.           }
  18.           // 在optionCount中增加计数
  19.           optionCount[result]++;
  20.         }
  21.       }
  22.     }
  23.   }
  24.   // 初始化最高分数和最高分数对应的评分结果
  25.   let maxScore = 0;
  26.   let maxScoreResult = null;
  27.   // 遍历评分结果列表
  28.   for (const result of question_results) {
  29.     // 计算当前评分结果的分数
  30.     const score = result.resultProp.reduce((count, prop) => {
  31.       return count + (optionCount[prop] || 0);
  32.     }, 0);
  33.     // 如果分数高于当前最高分数,更新最高分数和最高分数对应的评分结果
  34.     if (score > maxScore) {
  35.       maxScore = score;
  36.       maxScoreResult = result;
  37.     }
  38.   }
  39.   // 返回最高分数和最高分数对应的评分结果
  40.   return maxScoreResult;
  41. }
  42. const answerList = ["A"];
  43. const questions = [
  44.   {
  45.     title: "你通常更喜欢",
  46.     options: [
  47.       {
  48.         result: "I",
  49.         value: "独自工作",
  50.         key: "A",
  51.       },
  52.       {
  53.         result: "E",
  54.         value: "与他人合作",
  55.         key: "B",
  56.       },
  57.     ],
  58.   },
  59. ];
  60. const question_results = [
  61.   {
  62.     resultProp: ["I", "S", "T", "J"],
  63.     resultDesc: "忠诚可靠,被公认为务实,注重细节。",
  64.     resultPicture: "icon_url_istj",
  65.     resultName: "ISTJ(物流师)",
  66.   },
  67. ];
  68. console.log(getMaxScore(answerList, questions, question_results));
复制代码
留意:AI结果不稳固,可以连续优化

代码整合

修改代码并新建src/utis/bitUtils.ts
  1. /**
  2. * 获取最佳题目评分结果
  3. * @param answerList
  4. * @param questions
  5. * @param question_results
  6. */
  7. function getBestQuestionResult(answerList, questions, question_results) {
  8.   // 初始化一个对象,用于存储每个选项的计数
  9.   const optionCount = {};
  10.   // 遍历题目列表
  11.   for (const question of questions) {
  12.     // 遍历答案列表
  13.     for (const answer of answerList) {
  14.       // 遍历题目中的选项
  15.       for (const option of question.options) {
  16.         // 如果答案和选项的key匹配
  17.         if (option.key === answer) {
  18.           // 获取选项的result属性
  19.           const result = option.result;
  20.           // 如果result属性不在optionCount中,初始化为0
  21.           if (!optionCount[result]) {
  22.             optionCount[result] = 0;
  23.           }
  24.           // 在optionCount中增加计数
  25.           optionCount[result]++;
  26.         }
  27.       }
  28.     }
  29.   }
  30.   // 初始化最高分数和最高分数对应的评分结果
  31.   let maxScore = 0;
  32.   let maxScoreResult = question_results[0];
  33.   // 遍历评分结果列表
  34.   for (const result of question_results) {
  35.     // 计算当前评分结果的分数
  36.     const score = result.resultProp.reduce((count, prop) => {
  37.       return count + (optionCount[prop] || 0);
  38.     }, 0);
  39.     // 如果分数高于当前最高分数,更新最高分数和最高分数对应的评分结果
  40.     if (score > maxScore) {
  41.       maxScore = score;
  42.       maxScoreResult = result;
  43.     }
  44.   }
  45.   // 返回最高分数和最高分数对应的评分结果
  46.   return maxScoreResult;
  47. }
  48. const answerList = ["B","B","B","A"];
  49. const questions = [
  50.   {
  51.     title: "你通常更喜欢",
  52.     options: [
  53.       {
  54.         result: "I",
  55.         value: "独自工作",
  56.         key: "A",
  57.       },
  58.       {
  59.         result: "E",
  60.         value: "与他人合作",
  61.         key: "B",
  62.       },
  63.     ],
  64.   },
  65.   {
  66.     options: [
  67.       {
  68.         result: "S",
  69.         value: "喜欢有结构和常规",
  70.         key: "A",
  71.       },
  72.       {
  73.         result: "N",
  74.         value: "喜欢自由和灵活性",
  75.         key: "B",
  76.       },
  77.     ],
  78.     title: "对于日常安排",
  79.   },
  80.   {
  81.     options: [
  82.       {
  83.         result: "P",
  84.         value: "首先考虑可能性",
  85.         key: "A",
  86.       },
  87.       {
  88.         result: "J",
  89.         value: "首先考虑后果",
  90.         key: "B",
  91.       },
  92.     ],
  93.     title: "当遇到问题时",
  94.   },
  95.   {
  96.     options: [
  97.       {
  98.         result: "T",
  99.         value: "时间是一种宝贵的资源",
  100.         key: "A",
  101.       },
  102.       {
  103.         result: "F",
  104.         value: "时间是相对灵活的概念",
  105.         key: "B",
  106.       },
  107.     ],
  108.     title: "你如何看待时间",
  109.   },
  110. ];
  111. const question_results = [
  112.   {
  113.     resultProp: ["I", "S", "T", "J"],
  114.     resultDesc: "忠诚可靠,被公认为务实,注重细节。",
  115.     resultPicture: "icon_url_istj",
  116.     resultName: "ISTJ(物流师)",
  117.   },
  118.   {
  119.     resultProp: ["I", "S", "F", "J"],
  120.     resultDesc: "善良贴心,以同情心和责任为特点。",
  121.     resultPicture: "icon_url_isfj",
  122.     resultName: "ISFJ(守护者)",
  123.   },
  124. ];
  125. console.log(getBestQuestionResult(answerList, questions, question_results));
复制代码
可以修改测试用例,进入\src\utis目录终端进行测试node .\bizUtils.ts

导出函数,以便外部引用(src/utis/bitUtils.ts):
  1. export function getBestQuestionResult(answerList, questions, question_results) {
复制代码

页面间数据通报

需求:题目结果页面需要得到做题页面用户选择的答案列表,才能进行评分。


  • 方法 1:url params

    • https://taro-docs.jd.com/docs/apis/route/navigateTo
    • 比如:result?answerList=[A,B,C]

  • 方法 2:全局状态

    • https://taro-docs.jd.com/docs/context#contextprovider

  • 方法 3:本地数据存储(推荐,较为简单)

    • https://taro-docs.jd.com/docs/apis/storage/setStorageSync

做题页面通报数据src/pages/doQuestion/index.tsx

  1.       {current == questions.length && (
  2.         <AtButton
  3.           type="primary"
  4.           circle
  5.           className="controlBtn"
  6.           disabled={!currentAnswer}
  7.           onClick={() => {
  8.             // 传递答案列表
  9.             Taro.setStorage({
  10.               key:"answerList",
  11.               data:answerList
  12.             });
  13.             // 跳转结果页面
  14.             Taro.navigateTo({
  15.               url: "/pages/result/index",
  16.             });
  17.           }}
  18.         >
  19.           查看结果
  20.         </AtButton>
  21.       )}
复制代码

结果页面使用数据src/pages/result/index.tsx

  1.   // 获取从答题页面传递过来的答案列表
  2.   const answerList = Taro.getStorageSync("answerList");
  3.   if (!answerList || answerList.length < 0) {
  4.     Taro.showToast({
  5.       title: "答案为空!",
  6.       icon: "error",
  7.       duration: 2000
  8.     });
  9.   }
  10.   // 根据答案列表获取对应的测试结果
  11.   const result = getBestQuestionResult(answerList, questions, questionResults);
复制代码

MBTI 性格测试小程序测试



留意事项

出现题目在清除代码题目的环境下:


  • 清算开发工具缓存
  • 重启项目
  • 重启微信开发者工具
扩展



  • 美满MBTI性格测试小程序(参考http://sssch.net/ArticleDetail.aspx?ArticleID=13188130318)
  • 做题进度条
  • 优化结果样式(联合每种性格和用户性别展示差别的图片)
  • 将数据放进后端管理
进度条

在答题页面src/pages/doQuestion/index.tsx添加taro-ui的进度条组件,使用用户的答题数除以题目数计算即可:
  1.       <AtProgress
  2.         className="progress"
  3.         // 进度条的百分比
  4.         percent={(answerList.length / questions.length) * 100}
  5.         // 进度条的宽度
  6.         strokeWidth={10}
  7.         // 进度条的颜色
  8.         activeColor="#1aad19"
  9.       />
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

伤心客

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表