Vue 组件封装之 Questionnaire 问卷调查
前言
问卷调查表也是目前前端比较常见的开发项目,目前比较成熟的现成的问卷调查工具有番茄表单,问卷星等。那么如果要自己实现一个类型的问卷项目,应该如何入手呢,本文主要分享通过 vue 封装一个调查问卷组件。有了这个组件,基本调查问卷形式(包含填空,单选,多选形式的)都可以直接使用。本组件的封装是建立在element ui的 el-alert 组件、el-form-item组件、el-radio-group组件、el-radio组件、el-checkbox-group组件及el-checkbox组件的基础上,其实也就是对element ui 的单选多选组件进行二次封装,可以直接用于调查问卷。
一、Questionnaire 组件
组件说明:
实现问卷调查。
效果展示:
二、使用案例
<template>
<div>
<el-questionnaire
ref="mychild"
:objSource="displayObj"
:dataSource="dataSource"
:load="loading"
:item="item"
:isDisabled="isDisabled"
:isPlaceholder="isPlaceholder"
btnText="提交"
/>
</template>
<script>
export default{
data(){
return {
item:{name:"问卷调查",status:"edit"},
isDisabled:false,
loading:false,
isPlaceholder:"",
dataSource: [
{
title: '一、基本情况',
shortOption: [
{label: "姓名", paramStr: "name", placeholder: "请输入姓名", value: "", errorMsg: "请输入姓名"},
{label: '电话', paramStr: "mobile", placeholder: "请输入电话", value: "", errorMsg: "请输入电话"}
],
isChildAnswer: "1",
value: "1",
},
{
title: '二、工作情况', shortOption: [],
choiceOption: [
{
value: [],
paramStr: "gradate",
title: "工作几年?",
type:"checkbox",
list: ['1年-3年', "3年-5年", "5年以上"],
errorMsg: "请选择工作年限,如果选择了其他,请填写"
},
{
value: "",
paramStr: "job",
isOther: true,
title: "从事什么职业",
otherValue: "",
list: ['前端开发', "后端开发", "测试", "产品经理"],
errorMsg: "请选择所从事的职业"
},
],
isChildAnswer: "1",
value: "1",
},
{
title: '三、其他情况', shortOption: [],
choiceOption: [
{
value: "",
paramStr: "fruit",
title: "是否喜欢吃水果",
otherValue: "",
isChildAnswer: "是",
list: ['是', '否'],
errorMsg: "请选择是否喜欢吃水果",
shortOption: [
{label: "最喜欢的水果种类", paramStr: "fruit_kind", placeholder: "请输入最喜欢的水果种类", value: "", errorMsg: "请输入最喜欢的水果种类"}
],
choiceOption: [{
value: "",
paramStr: "fruit_link",
title: "喜欢吃的水果",
otherValue: "",
list: ['苹果', '香蕉', '梨子'],
errorMsg: "请选择喜欢吃的水果"
}],
},
{
value: [],
type:"checkbox",
paramStr: "sport",
title: "喜欢什么运动",
isOther: true,
otherValue: "",
list: ['篮球', '足球', '羽毛球'],
errorMsg: "请选择喜欢的运动"
},
],
isChildAnswer: "1",
value: "1",
}
],
displayObj:{},
}
},
},
methods:{
}
}
</script>
三、API 使用指南
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
objSource | 反显答案的数据源 | Object | {} |
dataSource | 题目的数据源 | Array | [] |
load | 初始加载的loading图 | Boolean | true |
item | 包含问卷名称以及是反显状态还是编辑状态 | Object | {} |
isDisabled | 是否禁用 | Boolean | false |
isPlaceholder | 是否显示提示文字 | Boolean | true |
btnText | 提交的按钮文字 | String | 提交 |
item的选项:
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
name | 问卷标题名称 | String | 问卷调查 |
status | 问卷状态,是编辑还是反显答案 | String | edit |
dataSource题目数据源的选项
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
title | 标题 | String | “” |
choiceOption | 选择题的问卷题目集合 | Array | [] |
shortOption | 填空题的问卷题目集合 | Array | [] |
isChildAnswer | 是否有子数据以及子数据出现的答案 | any | 无 |
value | 用户选中的值 | String | 无 |
choiceOption选择题的问卷题目集合参数说明
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
value | 用户选中的值 | String | 无 |
paramStr | 需要给后台传的字段 | String | 无 |
title | 题目标题 | String | 无 |
list | 选择题的选项数组 | Array | [] |
errorMsg | 对非空校验的提示框 | String | 无 |
isChildAnswer | 是否展示第二级问卷的答案 | String | 无 |
isOther | 是否有其他选项 | Boolean | true |
otherValue | 其他选项的答案 | String | 无 |
shortOption填空题的问卷题目集合参数说明
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
label | 填空题问题 | String | “” |
paramStr | 需要给后台传的字段 | String | 无 |
placeholder | 输入框提示文字 | String | 无 |
value | 用户输入的值 | any | 无 |
errorMsg | 对非空校验的提示框 | String | 无 |
isChildAnswer | 是否展示第二级问卷的答案 | any | 无 |
isArea | 是否是textarea多行输入框 | Boolean | true |
备注:isChildAnswer与value结合使用,两者相等时出现第二级问卷。比如是否喜欢吃水果,答案为是。(isChildAnswer设置为‘是’),则出现喜欢吃什么样的水果调查,如果选了不是,则不进行下一级答问。
四、源代码
List.vue(用于填空题)
<template>
<div
:class="disabled == 'disabled'?'list-bg-disabled':(item.value==''?'':'list-bg')">
<div class="cm-plr-10 cm-bottom">
<div class="cm-flex cm-fw-bold cm-ai-c" v-if="!item.isArea">
<label for=""><span class="cm-c-red" v-if="item.errorMsg"> * </span>
{{item.label}}
</label>
<input v-model="item.value"
:placeholder="isPlaceholder!='无'?item.placeholder:isPlaceholder"
class="list-input" :disabled="disabled"/>
</div>
<div class="cm-fw-bold" v-if="item.isArea">
<div class="cm-pt-10"><span class="cm-c-red" v-if="item.errorMsg"> * </span>{{item.label}}</div>
<textarea v-model="item.value"
maxlength="500"
:placeholder="isPlaceholder!='无'?item.placeholder:isPlaceholder"
:class="disabled == 'disabled'?'list-textarea-disabled':(item.value!=''?'list-textarea-value':'list-textarea')"
:disabled="disabled"
/></textarea>
</div>
<el-alert v-if="item.value == ''&& isShow && item.errorMsg"
:title="item.errorMsg"
type="error" show-icon
effect="light">
</el-alert>
</div>
</div>
</template>
<script>
import '../index.css';
export default {
name: 'List',
data () {
return {
}
},
props: {
item: {
type: Object,
default: {}
},
isShow: {
type: Boolean,
default: false
},disabled:{
default: false
},isPlaceholder:{
type: String,
default: ""
}
},
methods:{},
created(){},
}
</script>
<style scoped>
.list-input{
height: 3rem;
text-align: right;
flex: 1;
font-size: 0.875rem;
color: #000;
opacity:1
}
input:disabled,input[disabled]{
color: #000;
opacity:1
}
textarea:disabled,textarea[disabled]{
color: #000;
opacity:1
}
.list-textarea{
font-size: 0.875rem;
color: #333;
width: 100%;
border: none;
margin: 0.5rem 0;
background: #fff;
outline: none;
}
.list-textarea-value{
font-size: 0.875rem;
color: #333;
width: 100%;
border: none;
margin: 0.5rem 0;
background: #f5f5f9;
outline: none;
}
.list-textarea-disabled{
background-color: #f5f5f5;
font-size: 0.875rem;
color: #333;
width: 100%;
border: none;
margin: 0.5rem 0;
outline: none;
}
.list-bg{
background: #f5f5f5;
}
.list-bg-disabled{
background-color: #f5f5f5;
}
input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{
font-size: 0.875rem;
}
</style>
Select.vue(用于单选和多选)
<template>
<div>
<el-form-item class="cm-bottom sel-mar-10 cm-fw-bold">
<div><span class="cm-c-red" v-if="items.errorMsg">* </span>{{items.title}}</div>
<el-radio-group v-model="items.value" v-if="items.type != 'checkbox'" class="cm-width-full">
<el-radio :label="item" v-for="(item,index) in items.list" :disabled="disabled" :key="index" class="sel-width-35"></el-radio>
<div class="cm-mb-10 cm-flex cm-ai-c" v-if="items.isOther">
<el-radio label="其他" class="sel-width-35" :disabled="disabled"></el-radio>
<input class="sel-input" v-model="items.otherValue" :disabled="disabled" placeholder="请输入" v-if="items.value == '其他'"/>
</div>
<el-alert v-if="(items.value == ''||items.value == '其他' && !items.otherValue) && isShow && items.errorMsg"
:title="items.errorMsg"
type="error" show-icon
effect="light">
</el-alert>
</el-radio-group>
<el-checkbox-group v-model="items.value" v-if="items.type == 'checkbox'" class="cm-width-full sel-line-height">
<el-checkbox name="type" :disabled="disabled" :label="item" v-for="(item,index) in items.list" :key="index" class="sel-width-35"></el-checkbox>
<div class="cm-mb-10 cm-flex cm-ai-c" v-if="items.isOther">
<el-checkbox label="其他" :disabled="disabled" class="sel-width-35 sel-checkbox-mr"></el-checkbox>
<input class="sel-input" maxlength="20" v-model="items.otherValue" :disabled="disabled" placeholder="请输入" v-if="items.value &&(items.value != null) && items.value.indexOf('其他')>-1"/>
</div>
<el-alert v-if="(items.value && items.value.length == 0||(items.value.indexOf('其他')>-1 && !items.otherValue)) && isShow && items.errorMsg"
:title="items.errorMsg"
type="error" show-icon
effect="light"
>
</el-alert>
</el-checkbox-group>
</el-form-item>
<slot v-if="items.value == items.isChildAnswer"></slot>
</div>
</template>
<script>
import '../index.css';
let self;
export default {
name: 'Select',
data () {
return {
}
},
props: {
items: {
type: Object,
default: {}
},
isShow: {
type: Boolean,
default: false
},disabled:{
default: false
},type:{
type: String,
default: ""
}
},
created(){
self=this;
},
methods:{},
}
</script>
<style>
.sel-width-35{
width: 40%;
line-height: 40px;
}
.sel-checkbox-mr{
margin-right: 30px!important;
}
.sel-mar-10{
padding:0 1rem;
margin-bottom: 0;
}
.sel-input{
-webkit-appearance: none;
border-radius: 4px;
border: 1px solid #DCDFE6;
box-sizing: border-box;
color: #606266;
font-weight: 500;
font-size: 0.875rem;
opacity:1;
outline: 0;
height: 2rem;
padding: 0 0.3rem;
width: 150px;
}
input:disabled,input[disabled]{
color: #606266;
font-weight: 500;
opacity:1
}
textarea:disabled,textarea[disabled]{
color: #606266;
font-weight: 500;
opacity:1
}
.sel-line-height{
line-height: 1;
}
.el-checkbox__input.is-disabled+span.el-checkbox__label{
color: #606266!important;
opacity:1
}
.el-radio__input.is-disabled+span.el-radio__label{
color: #606266!important;
opacity:1
}
</style>
Questionnaire.vue
<template>
<div v-loading="load"
element-loading-text="提交中,请稍候..."
element-loading-spinner="el-icon-loading"
v-loading.fullscreen.lock="load"
>
<div class="cm-flex cm-jc-c cm-ptb-08">
<div class="cm-fw-bold cm-pr-10 cm-fs-12">{{item.name}}</div>
</div>
<el-form>
<div v-for="itemOption in dataSource">
<div class="cm-bottom cm-pad-08-10 cm-fw-bold cm-fs-11">{{itemOption.title}}</div>
<el-list class="fs-0875" :isPlaceholder="isPlaceholder" :item="item" :disabled="isDisabled" :isShow="isShow" v-for="(item,index) in itemOption.shortOption"
:key="item.label"></el-list>
<el-select :items="list" :disabled="isDisabled" :isShow="isShow" :key="index" v-for="(list,index) in itemOption.choiceOption">
<div class="expand-style">
<el-list :item="item" :disabled="isDisabled" :isPlaceholder="isPlaceholder" :isShow="isShow" v-for="(item,index) in list.shortOption"
:key="item.label"></el-list>
<el-select :items="list" :disabled="isDisabled" :isPlaceholder="isPlaceholder" :isShow="isShow" :key="index"
v-for="(list,index) in list.choiceOption"></el-select>
</div>
</el-select>
</div>
<el-form-item class="cm-fw-bold">
<label class="cm-ml-10">其他建议 </label>
<div class="cm-flex flex-fill">
<textarea ref="textarea" maxlength="500" name="" id=""
:placeholder="isPlaceholder!='无'?'请输入您的建议':isPlaceholder"
v-model="other_advice"
class="hos-textarea"
:disabled="isDisabled"
></textarea>
</div>
</el-form-item>
<div class="hos-btn" @click="submitForm()" v-if="item.status=='edit'">{{btnText}}</div>
</el-form>
</div>
</template>
<script>
import '../index.css';
import select from './Select.vue';
import list from './List.vue';
let self;
export default {
name: 'ElQuestionnaire',
components: {
"el-select": select,
"el-list": list
},
data () {
return {
other_advice: '',
isShow:false
}
},
props:{
dataSource:{
type:Array,
default:[]
},
objSource:{
type:Object,
default:{}
},
load:{
type:Boolean,
default:true
},
item:{
type:Object,
default:{}
},
isDisabled:{
type:String|Boolean,
default:false
},
isPlaceholder:{
type:String,
default:""
},
btnText:{
type:String,
default:"提交"
}
},
created(){
self = this;
},
mounted(){
var textarea = document.getElementsByTagName("textarea");
//多行输入框高度自适应
setTimeout(function () {
for(var i=0;i<textarea.length;i++){
textarea[i].style.height = textarea[i].scrollHeight + 'px';
textarea[i].addEventListener('input',function (e) {
e.target.style.height = 'auto';
e.target.scrollTop = 0; //防抖动
e.target.style.height = e.target.scrollHeight + 'px';
})
}
},200)
},
methods: {
//提交
submitForm(){
self.isShow = true;
var arr = [];
var obj = {};
self.generate(self.dataSource,{},arr,obj);
obj = Object.assign(obj,{"other_advice":self.other_advice});
console.log(obj);
this.$parent.submit(arr,obj);
},
//将数据源轮循
generate: (list,displayObj,arr, obj) => {
list.map((item) => {
if(arr && obj){
if (item && item.value !== undefined && item && item.paramStr !== undefined) {
//多选如果有其他,将其他数值添加进去
let value;
//其他值不等于空并且不是填空
if(item.otherValue != "" && item.otherValue != undefined && !item.label){
if(item.type == "checkbox") {
if(!item.value.includes(item.otherValue)){
item.value.push(item.otherValue);
}
//有其他值反选值,但是其他label没有勾选,就将其他值去掉
if(item.value.includes(item.otherValue) && !item.value.includes('其他')){
item.value = item.value.filter((item1)=>{return item1 != item.otherValue});
}
value = item.value;
} else {
if(item.otherValue && item.value=='其他'){
value = item.otherValue;
}
}
}else {
console.log(item);
value = item.value;
//如果其他值为空,但是选择了“其他”,则需要校验
if(item.value.indexOf('其他')>-1||item.value=='其他'){
arr.push({"value": item.otherValue});
}
}
obj = Object.assign(obj, {[item.paramStr]: value});
if(item.errorMsg){
arr.push({"value": item.value});
}
}
if (item.isChildAnswer && item.value == item.isChildAnswer) {
if (item.shortOption && item.shortOption.length > 0) {
self.generate(item.shortOption, {},arr, obj);
}
if (item.choiceOption && item.choiceOption.length > 0) {
self.generate(item.choiceOption, {},arr, obj);
}
}
}else {
if (item && item.value !== undefined && item && item.paramStr !== undefined) {
if(displayObj[item.paramStr]){
if(item.type == "checkbox" && displayObj[item.paramStr] && displayObj[item.paramStr].length>0){
item.value = displayObj[item.paramStr];
let allList =item.list.concat(displayObj[item.paramStr]);
item.value.map((res)=>{
if(item.list.indexOf(res)<0){
item.isOther = true;
if(item.otherValue!=res){
item.otherValue = res;
}
}
});
//value去重
item.value = item.value.filter((item1,index)=>{
return item.value && item1 && item.value.indexOf(item1)==index
})
//如果返回的值中有与页面值不同的则添加到页面值中
item.list = allList.filter((item1,index)=>{
return (allList.indexOf(item1))==index && item1 && item1!=item.otherValue && item1!='其他'
});
}else if(item.list && item.type != "checkbox"){
if(item.list.indexOf(displayObj[item.paramStr])<0 && displayObj[item.paramStr]){
item.isOther = true;
item.value="其他";
item.otherValue = displayObj[item.paramStr];
}else{
item.value = displayObj[item.paramStr];
}
}else {
item.value = displayObj[item.paramStr];
}
}
}
if (item.isChildAnswer && item.value == item.isChildAnswer) {
if (item.shortOption && item.shortOption.length > 0) {
self.generate(item.shortOption,displayObj);
}
if (item.choiceOption && item.choiceOption.length > 0) {
self.generate(item.choiceOption,displayObj);
}
}
if(displayObj.other_advice){
self.other_advice = displayObj.other_advice;
}
}
});
return {obj, arr};
}
}
}
</script>
<style>
.expand-style {
font-size: 0.875rem;
/*background: #f5f5f5;*/
}
.fs-0875{
font-size: 0.875rem;
}
.hos-btn {
background: #409EFF;
color: #fff;
margin: 1rem;
padding: 0.8rem 0;
text-align: center;
border-radius: 0.5rem;
}
.hos-textarea {
margin: 0 1rem;
word-break: break-all;
resize: none;
border-radius: 0.3rem;
outline: none;
line-height: 1rem;
width: 100%;
border: 1px solid #ddd;
font-size: 0.8rem;
color: #333;
padding:0.5rem;
}
</style>
公共样式 index.css
/*init*/
body,p{
margin: 0;
padding: 0;
}
html{
/*font-size: 62.5%;*/
}
input{
border:none;
outline:none;
background: none;
}
input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{
color:#ccc;
}
/*layout*/
.cm-flex{
display: flex;
}
.cm-flex-col{
display: flex;
flex-direction: column;
}
.flex-fill{
flex: 1;
}
.cm-flex-dir{
flex-direction: column;
}
.cm-jc-c{
justify-content: center;
}
.cm-jc-sb{
justify-content: space-between;
}
.cm-jc-sa{
justify-content: space-around;
}
.cm-ai-c{
align-items: center;
}
.cm-flex-row{
display: flex;
justify-content: center;
align-items: center;
}
.cm-flex-col-c{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.cm-as-end{
align-self: flex-end;
}
.cm-tx-c{
text-align: center;
}
.cm-tx-l{
text-align: left;
}
.cm-tx-r{
text-align: right;
}
/*margin/padding*/
.cm-mt-02{
margin-top: 0.2rem;
}
.cm-mt-03{
margin-top: 0.3rem;
}
.cm-mt-05{
margin-top:0.5rem;
}
.cm-mt-08{
margin-top:0.8rem;
}
.cm-mt-10{
margin-top: 1rem;
}
.cm-mt-12{
margin-top: 1.2rem;
}
.cm-mt-20{
margin-top: 2rem;
}
.cm-mar-10{
margin: 1rem;
}
.cm-mb-10{
margin-bottom: 1rem;
}
.cm-mb-20{
margin-bottom: 2rem;
}
.cm-mb-05{
margin-bottom:0.5rem;
}
.cm-mb-08{
margin-bottom:0.8rem;
}
.cm-mtb-02{
margin:0.2rem 0;
}
.cm-ml-10{
margin-left: 1rem;
}
.cm-m-10{
margin: 1rem;
}
.cm-ml-05{
margin-left: 0.5rem;
}
.cm-ml-03{
margin-left: 0.3rem;
}
.cm-mr-05{
margin-right: 0.5rem;
}
.cm-mr-03{
margin-right: 0.3rem;
}
.cm-mlr-03{
margin-left: 0.3rem;
margin-right: 0.3rem;
}
.cm-mlr-06{
margin-left: 0.6rem;
margin-right: 0.6rem;
}
.cm-mrl-percent1{
margin-left: 3%;
margin-right: 3%;
}
.cm-mlr-05{
margin-left: 0.5rem;
margin-right: 0.5rem;
}
.cm-mlr-10{
margin-left: 1rem;
margin-right: 1rem;
}
.cm-mtb-10{
margin-top: 1rem;
margin-bottom: 1rem;
}
.cm-mtb-08{
margin-top: 0.8rem;
margin-bottom: 0.8rem;
}
.cm-mtb-06{
margin-top: 0.6rem;
margin-bottom: 0.6rem;
}
.cm-m-05{
margin: 0.5rem;
}
.cm-mr-10{
margin-right: 1rem;
}
.cm-pt-03{
padding-top: 0.3rem;
}
.cm-pt-05{
padding-top: 0.5rem;
}
.cm-pt-10{
padding-top: 1rem;
}
.cm-pb-10{
padding-bottom: 1rem;
}
.cm-pb-05{
padding-bottom: 0.5rem;
}
.cm-ptb-10{
padding-top: 1rem;
padding-bottom: 1rem;
}
.cm-p-05{
padding: 0.5rem;
}
.cm-p-10{
padding: 1rem;
}
.cm-plr-06{
padding: 0 0.6rem;
}
.cm-plr-08{
padding: 0 0.8rem;
}
.cm-pl-10{
padding-left: 1rem;
}
.cm-pr-10{
padding-right: 1rem;
}
.cm-plr-10{
padding: 0 1rem;
}
.cm-plr-03{
padding: 0 0.3rem;
}
.cm-plr-05{
padding-left:0.5rem;
padding-bottom: 0.5rem;
}
.cm-ptb-03{
padding: 0.3rem 0;
}
.cm-ptb-05{
padding: 0.5rem 0;
}
.cm-ptb-08{
padding: 0.8rem 0;
}
.cm-pad-05-08{
padding: 0.5rem 0.8rem;
}
.cm-pad-08-05{
padding: 0.8rem 0.5rem;
}
.cm-pad-06-05{
padding: 0.6rem 0.5rem;
}
.cm-pad-05-10{
padding: 0.5rem 1rem;
}
.cm-pad-08-10{
padding: 0.8rem 1rem;
}
/*font*/
.cm-fw-bold{
font-weight: bold;
}
.cm-fs-06{
font-size: 0.6rem;
}
.cm-fs-07{
font-size: 0.7rem;
}
.cm-fs-08{
font-size: 0.8rem;
}
.cm-fs-09{
font-size: 0.9rem;
}
.cm-fs-10{
font-size: 1rem;
}
.cm-fs-11{
font-size: 1.1rem;
}
.cm-fs-12{
font-size: 1.2rem;
}
.cm-fs-14{
font-size: 1.4rem;
}
/*color*/
.cm-c-main{
}
.cm-c-red{
color: red;
}
.cm-c-white{
color: #fff;
}
.cm-c-gray{
color: #999;
}
.cm-c-blue{
color: #1890ff;
}
.cm-c-333{
color: #333;
}
.cm-c-000{
color: #000;
}
.cm-c-999{
color: #999;
}
.cm-c-666{
color: #666;
}
/*background*/
.cm-bc-main{
}
.cm-bc-white{
background: #fff;
}
.cm-bg-white{
background: #fff;
}
.cm-bottom{
border-bottom: 1px solid #dddddd;
}
.cm-border-top{
border-top: 1px solid #dddddd;
}
.cm-bottom-eee{
border-bottom: 1px solid #eeeeee;
}
.cm-border-radius{
border-radius: 50%;
}
.cm-img-20{
width: 2rem;
height: 2rem;
}
.cm-img-25{
width: 2.5rem;
height: 2.5rem;
}
.cm-img-30{
width: 3rem;
height: 3rem;
}
.cm-img-08{
width: 0.8rem;
height: 0.8rem;
}
.cm-img-10{
width: 1rem;
height: 1rem;
}
.cm-img-12{
width: 1.2rem;
height: 1.2rem;
}
.cm-img-13{
width: 1.3rem;
height: 1.3rem;
}
.cm-img-15{
width: 1.5rem;
height: 1.5rem;
}
.cm-width-full{
width: 100%;
}
.cm-size-100{
width: 100%;
height: 100%;
}
* {
-webkit-overflow-scrolling: touch;
}
转载:https://blog.csdn.net/weixin_44135121/article/details/99712896
查看评论