答题卡AnswerSheet效果封装(二)原生js封装插件,可以做答题卡业务模板

答题卡效果

在前端开发中,我们大量使用开源很多UI框架和js框架,让我们使用的越好,做项目越快,但是同时让我们也对最基本的css属性和js最基本和最底层的api都遗忘,所以我们通过自己封装插件和组件,让我们更容易拾起最基本的知识点;以下我会从3个部分总结这个过程:1.原生js和jquery实现基本tab效果,2.使用面向对象js和jquery常用封装方法,3.通过vue封装和优化AnswerSheet组件

核心js封装

/**
* 插件作用:
* 1. 切换效果
* 2. 封装初始化模板,前端不需要构建dom结构
* 3. 对数据的处理,传入数据,修改数据状态,返回更新后数据
* 4. 监测用户正在操作当前数据状态
*/
(function(window) {
   function AnswerSheet(options,callback) {
       var opts = Object.assign({}, AnswerSheet.defaultOptions, options);
       this.callback = callback;
       this.opts = opts;
       this.insertDom = opts.insertDom;
       this.questions = opts.questions;
       this.activeFiled = opts.activeFiled;
       this.currentIndex = 0;//记录当前题目的索引
       this.cardConts = null;//获取所有卡片node
       this.btnNodes = null;//下一个按钮node
       this.answerLables = null;//当前卡片的答案
       this.activedQuestionNode = null;//记录激活状态答案node
       this.init();
   }
   AnswerSheet.prototype = {
       constructor: AnswerSheet,
       init: function() {
           this.initData(this.questions);
           this.initTemplate(this.questions);
       },

       //初始化模板,
       initTemplate: function(data) {
           let strHtml = ` 
`; data.forEach((item, index) => { strHtml += `

${index + 1}.  ${item.question}

${item.answerList.length > 0 && this.renderChild(item.answerList)}
${index > 0 ? '上一题' : ''} ${index + 1}/ ${this.questions.length}
` }) strHtml += `
` this.insertDom.appendChild(this.strToNode(strHtml)); this.cardConts = document.querySelectorAll(".card_cont"); this.btnNodes = document.querySelectorAll(".prev"); this.answerLables =document.querySelectorAll(".answer-item"); //给答案绑定事件 this.bindEvent(this.answerLables,"click", this.nextHandler); //给上一个按钮绑定事件 this.bindEvent(this.btnNodes, "click", this.prevHandler); }, renderChild: function(answerList) { let strChild = `
`; answerList.forEach(item => { strChild += `
${item.lable}
` }) strChild += `
` return strChild; }, //初始化数据 initData: function(data) { data.forEach(item => { item.answerList.forEach(child => { child[this.activeFiled] = false; }) }); }, //初始化card编号 initCardNum: function() { }, //点击答案下一个卡片操作 nextHandler(e) { //设置激活状态 this.setActivedClass(e.target) //更新数据 this.updateData(e.target.textContent,this.currentIndex); let restCount = this.cardConts.length - (this.currentIndex + 1); if(restCount <= 0) { this.callback && this.callback(this.questions,this.currentIndex); return; } this.cardConts[this.currentIndex].classList.remove("card0"); this.cardConts[this.currentIndex].classList.add("cardn"); restCount >=1 && this.changeCardClass("next",1, this.cardConts[this.currentIndex]); restCount >=2 && this.changeCardClass("next",2, this.cardConts[this.currentIndex]); restCount >=3 && this.changeCardClass("next",3, this.cardConts[this.currentIndex]); this.currentIndex += 1; }, //点击上一个按钮卡片操作 prevHandler() { let rest2 = this.currentIndex; let rest = this.cardConts.length - (this.currentIndex + 1); if(rest2 <= 0) { alert("上面没题了") return } //把当前变为cardn this.cardConts[this.currentIndex].classList.remove("card0"); this.cardConts[this.currentIndex].classList.add("card1"); //把上一个变为card0 rest2 >=1 && this.changeCardClass("prev", -1, this.cardConts[this.currentIndex]) //把下一个变为card0 rest >=1 && this.changeCardClass("prev",1, this.cardConts[this.currentIndex]); //把下下个变为card1 rest >=2 && this.changeCardClass("prev",2, this.cardConts[this.currentIndex]); //把下下下个变为card2 // rest >=2 && changeCardClass("prev",3, cardConts[currentIndex]); this.currentIndex -= 1; }, //获取当前card的相邻的卡片,处理相邻卡片类名变化 changeCardClass(type, num, currentNode) { let _temp = null; switch (num) { case -1: _temp = currentNode.previousElementSibling; break; case 1: _temp = currentNode.nextElementSibling; break; case 2: _temp = currentNode.nextElementSibling.nextElementSibling; break; case 3: _temp = currentNode.nextElementSibling.nextElementSibling.nextElementSibling; break; default: break; } //区分上一个和下一个操作 if(type == "next") { _temp.classList.remove("card" + num); _temp.classList.add("card" + (num - 1)); }else { if(num < 1) { _temp.classList.remove("cardn"); _temp.classList.add("card0"); }else { _temp.classList.remove("card" + num); _temp.classList.add("card" + (num + 1)); } } }, //给选中答案设置激活样式 setActivedClass: function(node) { //把兄弟node去除actice let siblingNodes = node.parentNode.childNodes; siblingNodes.forEach(item => { item.classList.remove("active"); }) node.classList.add("active"); }, //修改数据状态 updateData: function(value, index) { console.log(value, index); let question = this.questions[index]; question.answerList.forEach(item => { item[this.activeFiled] = false; }) let answer = question.answerList.find(item => item.lable == value); answer[this.activeFiled] = true; console.log(this.questions) }, //绑定事件 bindEvent: function(node, event, cb) { if(node.length >= 0) { Array.prototype.forEach.call(node, item => { item.addEventListener(event, (e) => { cb && cb.call(this,e); }, false) }) }else { node.addEventListener(event, (e) => { cb && cb.call(this,e); }, false) } }, //字符串转换成 DOM对象 strToNode: function(strHtml) { return new DOMParser().parseFromString(strHtml,'text/html').body.childNodes[0]; } } AnswerSheet.defaultOptions = { insertDom: null,//设置要插入的节点 questions: [],//传入题目数据,结构是有要求的,层级感 activeFiled: "checked",//设置答案的激活状态字段 } return window.AnswerSheet = AnswerSheet; })(window)

使用

  • data - 模拟数据源
var data = [
   {
       id: "001",
       question: "这是第一个问题",
       answerList: [
           {
               id:"001",
               lable: "A",//这个是前端展示的字段,根据自己业务需求进行设置
               value: 10// 这个是后台真实所处理的字段,根据自己业务需求进行设置
           },{
               id:"002",
               lable: "B",
               value: 20
           },{
               id:"003",
               lable: "C",
               value: 10
           },{
               id:"004",
               lable: "D",
               value: 20
           }
       ]
   },{
       id: "002",
       question: "这是第二个问题",
       answerList: [
           {
               id:"001",
               lable: "A",//这个是前端展示的字段,根据自己业务需求进行设置
               value: 10// 这个是后台真实所处理的字段,根据自己业务需求进行设置
           },{
               id:"002",
               lable: "B",
               value: 20
           },{
               id:"003",
               lable: "C",
               value: 10
           },{
               id:"004",
               lable: "D",
               value: 20
           }
       ]
   },{
       id: "003",
       question: "这是第三个问题",
       answerList: [
           {
               id:"001",
               lable: "A",//这个是前端展示的字段,根据自己业务需求进行设置
               value: 10// 这个是后台真实所处理的字段,根据自己业务需求进行设置
           },{
               id:"002",
               lable: "B",
               value: 20
           },{
               id:"003",
               lable: "C",
               value: 10
           },{
               id:"004",
               lable: "D",
               value: 20
           }
       ]
   },{
       id: "004",
       question: "这是第四个问题",
       answerList: [
           {
               id:"001",
               lable: "A",//这个是前端展示的字段,根据自己业务需求进行设置
               value: 10// 这个是后台真实所处理的字段,根据自己业务需求进行设置
           },{
               id:"002",
               lable: "B",
               value: 20
           },{
               id:"003",
               lable: "C",
               value: 10
           },{
               id:"004",
               lable: "D",
               value: 20
           }
       ]
   },{
       id: "005",
       question: "这是第五个问题",
       answerList: [
           {
               id:"001",
               lable: "A",//这个是前端展示的字段,根据自己业务需求进行设置
               value: 10// 这个是后台真实所处理的字段,根据自己业务需求进行设置
           },{
               id:"002",
               lable: "B",
               value: 20
           },{
               id:"003",
               lable: "C",
               value: 10
           },{
               id:"004",
               lable: "D",
               value: 20
           }
       ]
   }
]


  • html



   
   
   
   答题卡
   


   

效果

1619167053(1).jpg

下次更新使用vue封装AnswerSheet组件
使用vue封装组的新功能:

  1. 根据题目种类变颜色
  2. 可以人工播放题目功能
    万水千山总是情,点波关注行不行呦!!!

你可能感兴趣的:(答题卡AnswerSheet效果封装(二)原生js封装插件,可以做答题卡业务模板)