This is the 8th day of my participation in the More text Challenge. For details, see more text Challenge

For the student party, the most common is the test paper, questionnaire test questions and so on, is there a paper is the management of the test question bank? For those of you who are just starting out, read this article carefully and make sure you can handle the code yourself after reading it.

1, exam questions

There are many kinds of questions in the examination paper, the common ones are single choice, multiple choice, fill in the blank, picture questions and so on, such as the questionnaire questions in the picture below.

2. Component definition

So many questions, their interfaces and forms of operation have similarities and differences, so we can simply design components according to the questions.

We first create a WQuestionItem folder, and then add each type of question component:

  • ImageSingleItem: Image multiple choice
  • B: It’s a MultiItem
  • SingleItem: Multiple choice
  • TextItem: Fill in the blanks
  • A NumItem
  • .

2.1 Design of single question type components

Everything is difficult at the beginning. If we can design the single question successfully, then multiple question types may just have different choices and results.

So when designing a single choice component, we had to work a little harder.

Okay, look at the component class diagram for the design.A single question component is best suited to implement as a response input, and a component that returns a resultv-modelTwo-way binding behavior. We’ve all tried each of the VUE components of ElementUI, and that design is pretty good, so let’s take a look at the following.

Vue official explanation:

A V-Model on a component will by default utilize a prop named value and an event named Input

However, input controls of types such as checkboxes, checkboxes, and so on May use the Value attribute for different purposes. Using the Model option can be used to avoid such conflicts.

2.1.1 Template Design

We use ElementUI as the primary output UI. Using el-Card on the layout, just put the title of the question in the header area and the options in the data area.

<template>
  <div>
    <el-card class="box-card" :shadow="shadow" :body-style="bodyStyle">
      <div slot="header" class="clearfix">
        <el-row type="flex" justify="space-between">
          <el-col :span="20">
            <h3>{{ question.title }}</h3>
          </el-col>
          <el-col :span="4" style="width:300px; text-align:right;">
          </el-col>
        </el-row>
      </div>
      <el-form
        ref="form"
        :model="answer"
        label-width="20px"
        label-position="top"
        size="medium"
        class="question"
      >
        <template>
          <el-form-item>
            <el-radio-group ref="rg" :value="answer.content" @input="handleInput">
              <el-col
                v-for="(item, index) in question.items"
                :key="index"
                :class="className"
                style="margin-bottom:20px;"
                @mouseover.native="hover($event)"
                @mouseout.native="removeClass($event)"
              >
                <el-radio :label="item.index">{{ item.content }}</el-radio>
              </el-col>
            </el-radio-group>
          </el-form-item>
        </template>
      </el-form>
    </el-card>
  </div>
</template>
Copy the code

Native =”hover($event)” @mouseout.native=”removeClass($event)”

2.1.2 Component code Implementation 1

Predictably, there must be some code in the component that needs to be shared, so we designed hybrid classes to duplicate functionality.

export const CommonItem = {
  data() {
    return {
      className: ' '.activeName: 0,}},created() {
    // console.log(' this is the creation of a mixed object ')
  },
  methods: {
    hover(event) {
      event.currentTarget.className = 'bold'
    },
    removeClass(event) {
      event.currentTarget.className = ' '}},computed: {
    shadow() {
      return this.question.child ? 'never' : 'always'
    },
    bodyStyle() {
      return this.question.child ? 'min-height:320px ; background-color: transparent'
        : 'min-height:320px ; background: -webkit-linear-gradient(top,rgba(234, 240, 184, 0.212), Rgba (224, 221, 172, 0.507), RGB (234, 240, 184)) no-repeat; '}},}Copy the code

2.1.3 Component Code Implementation 2

Mixed classes serve as a base, and common code can be extracted into mixed classes at any time. Now it’s time for the code for the radio component implementation.


// Reference the mixed class
import { CommonItem } from './mixins'
export default {
  name: 'SingleItem'.mixins: [CommonItem],
  // Redefine the model name, we receive answer
  model: { 
    prop: 'answer'.event: 'input'
  },
  props: {
    / / the topic
    question: {
      type: Object.required: true.default: () = > {
        return{}}},answer: {
      type: Object}},}Copy the code

Redesign method, mainly handle input events. Note: The values of the options are placed in answer.content. $emit(‘input’, RTN); $emit(‘input’, RTN);

methods: {
    handleInput(value) {
      varrtn = { ... this.answer,content: value,
        state: value >= 0
      }
      console.log('single handleInput:', rtn)
      this.$emit('input', rtn)
    },
    handleKeyDown(e) {
      // console.log('key:',e.keyCode)
      if (e.keyCode > 48 && e.keyCode <= 57) {
        // 1 answer 0
        var index = (e.keyCode - 49)
        if (this.question.items.length > index && index >= 0) {
          var ans = index.toString()
          this.handleInput(ans)
        }
        e.preventDefault()
      }
    },
    handleKeyUp(e){},}Copy the code

2.2 Fill in the blanks component

Now that we’ve solved the multiple choice questions, let’s move on to the fill in the blanks component, because it’s easy, and the soft one starts with the soft one.

Copy the single option component and change it to textitem.vue. replace the el-form in the template:

<el-form
        ref="form"
        :model="answer"
        label-width="20px"
        label-position="top"
        size="medium"
        class="question"
      >
        <template>
          <el-form-item label="">
            <el-input
              type="textarea"
              :value="textVal"
              @input="handleInput"
            />
          </el-form-item>
        </template>
      </el-form>
Copy the code

2.2.1 Defining component Codes

Increase the data:

data() {
    return {
      textVal: Array.isArray(this.answer.content) ? ' ' : this.answer.content
    }
  },
Copy the code

2.2.2 Processing input

handleInput(value) {
 varrtn = { ... this.answer,content: value,
     state: value.length > 0
   }

   console.log('text handleInput:', rtn)
   this.$emit('input', rtn)
 },
Copy the code

2.3 Multiple choice component

Use Ctrl+C and Ctrl+V to modify the el-Form code:

<el-form
        ref="form"
        :model="answer"
        label-width="20px"
        label-position="top"
        size="medium"
        class="question"
      >
   <template>
     <el-form-item>
       <el-checkbox-group :value="answer.content" @input="handleInput">
         <el-col
           v-for="(item, index) in question.items"
           :key="index"
           style="margin-bottom: 20px"
           @mouseover.native="hover($event)"
           @mouseout.native="removeClass($event)"
         >
           <el-checkbox
             :label="item.index"
           >[{{item.index}}], {{item.content}}</el-checkbox>
         </el-col>
       </el-checkbox-group>
     </el-form-item>
   </template>
 </el-form>
Copy the code

All we need to do here is handle the input event, and we return an array as the answer to the multiple choice.

handleInput(value) {
      varrtn = { ... this.answer,content: [].state: value.length > 0
      }
      var arr = value || []
      arr.forEach(item= > {
        if(item ! =' '&& item ! ='1') {
          rtn.content.push(item)
        }
      })

      console.log('multi handleInput:', rtn)
      this.$emit('input', rtn)
    }
Copy the code

2.4 image problem

The picture question is a variant of the multiple-choice question, but the title is just a picture, so we just need to copy the multiple-choice question and change the title.

<el-image style="width: 381px; height: 411px" :src="question.title" lazy />
Copy the code

Ha ha, done.

3. Build the parent component

Now that the question components are built, we need a parent component that encapsulates the components for each question type. This combination is judged by the question type:

<template>
  <div>
    <template v-if="question.type=='single'">
      <single-item
        v-model="answerVal"
        :question="question"
        @input="handleInput"
      />
    </template>
    <template v-else-if="question.type=='multi'">
      <multi-item
        v-model="answerVal"
        :question="question"
        @input="handleInput"
      />
    </template>
    <template v-else-if="question.type=='image'">
      <image-single-item
        v-model="answerVal"
        :question="question"
        @input="handleInput"
      />
    </template>
    <template v-else-if="question.type=='text'">
      <text-item
        v-model="answerVal"
        :question="question"
        @input="handleInput"
      />
    </template>
    <template v-else>
      dont setup question type
    </template>
  </div>
</template>
Copy the code

The implementation code is as follows:

export default {
  name: 'WQuestionItem'.components: { SingleItem, MultiItem, TextItem, ImageSingleItem },
  model: {
    prop: 'answer'.event: 'input'
  },
  props: {    
    question: {
      type: Object.required: true.default: () = > {
        return{}}},answer: {
      type: Object}},data() {
    return {
      answerVal: JSON.parse(JSON.stringify(this.answer))
    }
  },
  computed: {},methods: {
    handleInput(val) {
      console.log('wquestionItem', val)
      this.$emit('input', val)
    }
  }
}
Copy the code

Run the effect ~~~~

4 summary

Using the components of VUE, we have realized the design of single choice, multiple choice, fill in the blank, picture and other questions. If you have more needs, you can easily expand on this basis.

Pay attention to me, don’t get lost; Study vue together, progress together!