1. 问卷调查页面源码
<template>
  <div>
    <van-nav-bar title="问卷调查" left-text="返回" left-arrow :fixed="true" />
    <div class="style-class">
      <questionList class="list-style" ref="listComponent" :question="data" />
      <div class="button-style">
        <van-button round block type="info" @click="submitInfo()"
          >提交</van-button
        >
      </div>
    </div>
  </div>
</template>

<script>
import questionList from "@/components/QuestionList";
// 问卷本地数据
import listData from "../../../mock/data";
export default {
  name: "Question",
  components: { questionList },
  data() {
    return {
      data: listData
    };
  },
  methods: {
    submitInfo() {
      const data = this.$refs.listComponent.getValues();
      console.log(data);
    }
  }
};
</script>
<style lang="scss" scoped>
.style-class {
  background-color: #f7f8fa;
  height: calc(100%);
  //margin-bottom: 50px; 取消下外边距
  margin-top: 46px;
}
// 按钮样式
.button-style {
  margin: 0px 36px 0px 36px;
  padding: 0px 0px 10px 0px;
}
// 问题列表样式
.list-style {
  padding: 0.1px 0px 0px 0px;
}
</style>

  1. 动态组件源码
<template>
  <div>
    <div v-for="(item, index) in question" :key="index">
      <!--通过v-if来控制组件的可见性,v-for key 遍历选项  key的主要作用就是用来提高渲染性能的!key属性可以避免数据混乱的情况出现 (如果元素中包含了有临时数据的元素,如果不用key就会产生数据混乱)-->
      <!--单选-->
      <div class="radio-div" v-if="'select' === item.type">
        <p class="label"></p>
        <van-radio-group
          v-model="item.value"
          v-for="(itemValue, index) in item.options"
          :key="index"
        >
          <van-radio :name="itemValue.value"></van-radio>
        </van-radio-group>
      </div>
      <!--单选 表格展示形式-->
      <div class="radio-div" v-if="'cell-select' === item.type">
        <p class="label"></p>
        <van-radio-group v-model="item.value">
          <van-cell-group
            v-for="(itemValue, index) in item.options"
            :key="index"
          >
            <van-cell
              clickable
              :title="itemValue.title"
              @click="cellSelectClick(item, itemValue)"
            >
              <van-radio :name="itemValue.value" slot="right-icon" />
            </van-cell>
          </van-cell-group>
        </van-radio-group>
      </div>
      <!--多选框-->
      <div class="radio-div" v-if="'checkbox' === item.type">
        <p class="label"></p>
        <van-checkbox-group
          v-model="item.value"
          v-for="(itemValue, index) in item.options"
          :key="index"
        >
          <van-checkbox :name="itemValue.value"></van-checkbox>
        </van-checkbox-group>
      </div>
      <!--文本多行输入-->
      <div class="radio-div" v-if="'text' === item.type">
        <p class="label"></p>
        <div class="div-field">
          <van-field
            v-model="item.value"
            rows="2"
            autosize
            type="textarea"
            maxlength="60"
            :placeholder="item.placeHolder"
            show-word-limit
            :border="false"
            clearable
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "QuestionList",
  props: {
    // 定义属性
    question: {
      type: Array
    }
  },
  methods: {
    // 单元格点击方法
    cellSelectClick(item, itemValue) {
      item.value = itemValue.value;
    },
    // 获取最终调查数据
    getValues() {
      let data = [];
      this.question.forEach(item => {
        data.push(item.value);
      });
      return data;
    }
  }
};
</script>
<style lang="scss" scoped>
// 单选框组的样式
.van-radio-group {
  margin: 0px 17.5px;
  .van-radio {
    margin: 0px 0px 11px;
  }
}
// 多选框组的样式
.van-checkbox-group {
  margin: 0px 17.5px;
  .van-checkbox {
    margin: 0px 0px 11px;
  }
}
// 文本输入的样式
.div-field {
  margin: 0px 17.5px;
  .van-field {
    margin: 0px 0px 11px;
  }
}
// 控制问题区域的样式
.radio-div {
  text-align: left;
  margin: 16px 16.5px;
  padding: 8px 0px;
  background-color: white;
  // 设置圆角
  -moz-border-radius: 10px;
  -webkit-border-radius: 10px;
  border-radius: 10px;
  .label {
    font-size: 16.4px;
    font-weight: bold;
    padding-left: 0.26667rem;
    margin: 10px 0px 14.2px 0px;
    padding: 0px 0px 0px 11px;
  }
}
.label:before {
  content: "* ";
  color: #3c6efe;
  left: 0;
  top: 0;
  box-sizing: border-box;
}
</style>