最近手上的项目要求做一个调查问卷(题目数据由后端返回,也就是说题目数量不定,题目类型分为单选、多选、简答、上传附件四种)

思路:

1、把每种题型单独封装成组件

2、统一拿到所有题目的数据,通过点击“下一题”、“上一题”拆分数据,通过题目类型控制显隐

3、选择答案后,点击“下一题”之前,this.$set()保存当前题目答案到该题

4、做完问卷后提交,拿到所有题目数据(包含答案),组装成后端需要的数据结构提交答案即可

上代码:

1、封装组件

1)单选题:

<template><!-- 单选题目 --><div class="Single-choice" v-if="dataObj.sexFlg=='0' || sexFlg==dataObj.sexFlg"><span v-show="dataObj.isRequired=='1'" class="isMust">*</span><p class="single-title">{{dataObj.orderNum}}、{{ dataObj.title }}</p><van-form ref="form"><van-radio-group@change="choosSingle"v-model="checked":rules="[{ required: true, message: '请做出选择' }]"><van-radiov-for="(item, key, index) in dataObj.optionItems"v-show="item.sexFlg=='0' || sexFlg==item.sexFlg":key="index":name="item.id">{{ item.title }}</van-radio></van-radio-group></van-form></div>
</template><script>
export default {name: "singledate",data() {return {checked: "",sexFlg:this.$route.query.sex//获取患者性别,选项根据性别匹配(1男2女0不限)};},props: {dataObj: {type: Object,},checkdata: {type: Number,},},computed: {},created() {},mounted() {if (this.checkdata) {this.checked = this.checkdata;}},methods: {choosSingle(val) {console.log(val);this.$emit("getvalue", val);},},
};
</script>
<style lang="scss" scoped>
.Single-choice {position: relative;.isMust {position: absolute;font-size: 0.56rem;color: #f35757;font-weight: initial;top: -0.11rem;left: -3px;}.single-title {margin-left: 3%;}
}.van-radio {margin-bottom: 0.43333rem;
}
.van-checkbox {margin-bottom: 0.43333rem;
}
</style>

2)多选题:(有其他选项,需要自己手动填写那种)

<template><!-- 复选题目 --><div class="multiple-choice" v-if="data.sexFlg=='0' || sexFlg==data.sexFlg"><span v-show="data.isRequired=='1'" class="isMust">*</span><p class="multiple-title">{{data.orderNum}}、{{ data.title }}</p><van-checkbox-group@change="choosMultdata"v-model="checked1"v-for="(item, key, index) in data.optionItems":key="index"><van-checkbox shape="square" :name="item" v-if="item.sexFlg=='0' || sexFlg==item.sexFlg">{{ item.title }}<div v-show="item.title == '其他'"><span class="other-choise">其他</span><span v-show="item.packRequired=='1'" class="isMust other">*</span><van-cell-group inset><van-field v-model="othervalue" /></van-cell-group></div></van-checkbox></van-checkbox-group></div>
</template><script>
export default {name: "multipledate",data() {return {checked1: [],// 选项其他checkedother: false,othervalue: "",sexFlg:this.$route.query.sex//获取患者性别,选项根据性别匹配(1男2女0不限)};},props: {data: {type: Object,},},computed: {},created() {},mounted() {},methods: {choosMultdata(val) {this.$emit("getMultvalue", val);},},// 监听其他类型数据,传给父组件watch: {othervalue: {handler(val) {if (val) {this.$emit("getotherVal", val);}},},},
};
</script>
<style lang="scss" scoped>
.multiple-choice {position: relative;width: 80%;.isMust {position: absolute;font-size: 0.56rem;color: #f35757;font-weight: initial;top: -0.11rem;left: -3px;}.other {top: 0;right: 1px;left: unset;}.multiple-title {margin-left: 3%;}.other-choise {position: absolute;top: 0.15rem;}
}.van-radio {margin-bottom: 0.43333rem;
}
.van-checkbox {margin-bottom: 0.43333rem;position: relative;height: 0.7rem;
}
.van-cell-group--inset {margin-left: 0.7rem;
}
.van-cell {background-color: #f5f5f5;height: 120px;
}
</style>

3)简答题:

<template><!-- 建议 --><div class="recommen" v-if="data.sexFlg=='0' || sex==data.sexFlg"><span v-show="data.isRequired=='1'" class="isMust">*</span><p class="recommen-title">{{data.orderNum}}、{{data.title}}</p><div class="textarea-content"><textarea name="test" id="recomsg" cols="40" rows="10" v-model="inputval"></textarea><span style="display: block; text-align: right; margin-right: 6%">您还可以输入{{ this.inputval==null?'100':this.titleMaxLength - this.inputval.length }}字</span></div></div>
</template><script>
export default {name: "recommend",data() {return {checked1: [],inputval: "",titleMaxLength: 100,// 性别sex:'0',};},props: {data: {type: Object,},},computed: {},created() {},mounted() {// 获取性别this.sex=this.$route.query.sex;// 处理题目根据性别显隐 性别 1 男 2 女 0无限},methods: {choosMultdata(val) {this.$emit("getMultvalue", val);},},watch: {inputval(val) {// if (this.inputval.length > this.titleMaxLength) {//   this.inputval = String(this.inputval).slice(0, this.titleMaxLength);// }this.$emit("getrecommendvalue", val);},},
};
</script>
<style lang="scss" scoped>
.recommen {position: relative;.isMust {position: absolute;font-size: 0.56rem;color: #f35757;font-weight: initial;top: -0.11rem;left: -3px;}#recomsg {background-color: #f6f6f6;border: unset;width: 87%;}.recommen-title {margin-left: 3%;}.textarea-content {width: 100%;text-align: center;}
}
</style>

4、上传附件(主要是图片)

<template><!-- 上传附件 --><div class="uploadImg" v-show="data.sexFlg == '0' || sex == data.sexFlg"><span v-show="data.isRequired == '1'" class="isMust">*</span><p class="uploadImg-title">{{ data.orderNum }}、{{ data.title }}</p><van-uploader:after-read="onRead":accept="'image/*'"v-model="fileList"multiple@delete="delImg":max-count="9"/></div>
</template><script>
export default {name: "uploadImg",data() {return {sex: "", //性别checked1: [],recmsg: "",titleMaxLength: 100,fileList: [],// 图片地址uploadUrl: [],};},props: {data: {type: Object,},},computed: {},created() {},mounted() {// 获取性别this.sex = this.$route.query.sex;},methods: {// 图片上传后onRead(file) {// 大于1MB的jpeg和png图片都缩小像素上传file.status = "uploading";file.message = "上传中...";// 如果是单张图片,fille是对象,当上传图片大于1M时,压缩上传if (file.file) {if (/\/(?:jpeg|png)/i.test(file.file.type) &&file.file.size > 1000000) {console.log("大于1Mb");// 创建Canvas对象(画布)let canvas = document.createElement("canvas");// 获取对应的CanvasRenderingContext2D对象(画笔)let context = canvas.getContext("2d");// 创建新的图片对象let img = new Image();// 指定图片的DataURL(图片的base64编码数据)img.src = file.content;// 监听浏览器加载图片完成,然后进行进行绘制img.onload = () => {var newWidth = img.width * 0.7; //压缩后图片的宽度var newHeight = img.height * 0.7; //压缩后图片的高度// 指定canvas画布大小,该大小为最后生成图片的大小canvas.width = newWidth;canvas.height = newHeight;/* drawImage画布绘制的方法。(0,0)表示以Canvas画布左上角为起点,400,300是将图片按给定的像素进行缩小。如果不指定缩小的像素图片将以图片原始大小进行绘制,图片像素如果大于画布将会从左上角开始按画布大小部分绘制图片,最后的图片就是张局部图。*/context.drawImage(img, 0, 0, newWidth, newHeight);// 将绘制完成的图片重新转化为base64编码,file.file.type为图片类型,0.92为默认压缩质量file.content = canvas.toDataURL(file.file.type, 0.7);let data = {dirtype: "hlfw",message: file.content,};this.$post("/uploadImg", data).then((res) => {if (res.result == "success") {file.uploadUrl = res.url;this.uploadUrl.push(file.uploadUrl);// 给父组件this.$emit("accessAttachment", this.uploadUrl);this.$emit("getfilelist", this.fileList);this.$toast(res.info);file.status = "";file.message = "";} else {this.$toast(res.info);file.status = "failed";file.message = "上传失败";if (!this.fileList[this.fileList.length - 1].uploadUrl) {this.fileList.splice(this.fileList.length - 1, 1);}}}).catch((err) => {console.log(err);this.$toast("上传超时 请重试");file.status = "failed";file.message = "上传失败";if (!this.fileList[this.fileList.length - 1].uploadUrl) {this.fileList.splice(this.fileList.length - 1, 1);}});};} else {let data = {dirtype: "hlfw",message: file.content,};this.$post("/uploadImg", data).then((res) => {if (res.result == "success") {file.uploadUrl = res.url;this.uploadUrl.push(file.uploadUrl);// 给父组件this.$emit("accessAttachment", this.uploadUrl);this.$emit("getfilelist", this.fileList);file.status = "";file.message = "";} else {this.$toast(res.info);file.status = "failed";file.message = "上传失败";if (!this.fileList[this.fileList.length - 1].uploadUrl) {this.fileList.splice(this.fileList.length - 1, 1);}}}).catch((err) => {console.log(err);file.status = "failed";file.message = "上传失败";this.$toast("上传超时 请重试");if (!this.fileList[this.fileList.length - 1].uploadUrl) {this.fileList.splice(this.fileList.length - 1, 1);}});}}// 如果是批量,file就是数组else {for (let i = 0; i < file.length; i++) {if (/\/(?:jpeg|png)/i.test(file[i].file.type) &&file[i].file.size > 1000000) {console.log("大于1Mb");// 创建Canvas对象(画布)let canvas = document.createElement("canvas");// 获取对应的CanvasRenderingContext2D对象(画笔)let context = canvas.getContext("2d");// 创建新的图片对象let img = new Image();// 指定图片的DataURL(图片的base64编码数据)img.src = file[i].content;// 监听浏览器加载图片完成,然后进行进行绘制img.onload = () => {var newWidth = img.width * 0.7; //压缩后图片的宽度var newHeight = img.height * 0.7; //压缩后图片的高度// 指定canvas画布大小,该大小为最后生成图片的大小canvas.width = newWidth;canvas.height = newHeight;/* drawImage画布绘制的方法。(0,0)表示以Canvas画布左上角为起点,400,300是将图片按给定的像素进行缩小。如果不指定缩小的像素图片将以图片原始大小进行绘制,图片像素如果大于画布将会从左上角开始按画布大小部分绘制图片,最后的图片就是张局部图。*/context.drawImage(img, 0, 0, newWidth, newHeight);// 将绘制完成的图片重新转化为base64编码,file.file.type为图片类型,0.92为默认压缩质量file[i].content = canvas.toDataURL(file[i].file.type, 0.7);let data = {dirtype: "hlfw",message: file[i].content,};this.$post("/uploadImg", data).then((res) => {if (res.result == "success") {file[i].uploadUrl = res.url;this.uploadUrl.push(file[i].uploadUrl);// 给父组件this.$emit("accessAttachment", this.uploadUrl);this.$emit("getfilelist", this.fileList);this.$toast(res.info);file.status = "";file.message = "";} else {this.$toast(res.info);file.status = "failed";file.message = "上传失败";if (!this.fileList[this.fileList.length - 1].uploadUrl) {this.fileList.splice(this.fileList.length - 1, 1);}}}).catch((err) => {console.log(err);this.$toast("上传超时 请重试");file.status = "failed";file.message = "上传失败";if (!this.fileList[this.fileList.length - 1].uploadUrl) {this.fileList.splice(this.fileList.length - 1, 1);}});};} else {let data = {dirtype: "hlfw",message: this.fileList[i].content,};this.$post("/uploadImg", data).then((res) => {if (res.result == "success") {file[i].uploadUrl = res.url;this.uploadUrl.push(file[i].uploadUrl);// 给父组件this.$emit("accessAttachment", this.uploadUrl);this.$emit("getfilelist", this.fileList);file[i].status = "";file[i].message = "";} else {this.$toast(res.info);file[i].status = "failed";file[i].message = "上传失败";if (!this.fileList[this.fileList.length - 1].uploadUrl) {this.fileList.splice(this.fileList.length - 1, 1);}}}).catch((err) => {console.log(err);console.log(this.fileList);file[i].status = "failed";[i].message = "上传失败";this.$toast("上传超时 请重试");if (!this.fileList[this.fileList.length - 1].uploadUrl) {this.fileList.splice(this.fileList.length - 1, 1);}});}}}},//删除预览图片按钮delImg(e) {console.log("删除的图片", e);this.$emit("getfilelist", this.fileList);//  this.fileList.splice(this.fileList.length - 1, 1);},},watch: {recmsg() {if (this.recmsg.length < 10) {//  this.$toast.fail("请至少输入10个字");}if (this.recmsg.length > this.titleMaxLength) {this.recmsg = String(this.recmsg).slice(0, this.titleMaxLength);}},},
};
</script>
<style lang="scss" scoped>
.uploadImg {position: relative;.isMust {position: absolute;font-size: 0.56rem;color: #f35757;font-weight: initial;top: -0.11rem;left: -3px;}.uploadImg-title {margin-left: 3%;}
}
</style>

2、将以上子组件引入父组件内 三大步:importent...  component注册  html添加(这里的缓存不建议在这里写,还是用路由里面的meta:keepalive来控制)

3、从后端获取全部题目数据,其大致结构如下:

这个结构稍微有点复杂,但是我们一题一题去拆分就会比较清晰了

进入页面,在mounted里面我们首先把数组的第一项赋值给第一题,我们通过每一题的topicType来控制题目的显隐,上面引入组件那里可以看到

// 获取题目数据//getdataArr() {let id = this.$route.query.id;let sex = this.$route.query.sex;this.$post("/followup/topicDetail", { baseId: id, sexFlg: sex }).then((res) => {if (res.result == "success") {// 大标题this.title=res.baseInfo.memothis.dataArr = res.rows;this.pagecount = res.rows.length;this.theCurrentValue = this.dataArr[0];//数组第一项给第一题this.topicType = this.theCurrentValue.topicType;//获取当前题目类型// 获取参数this.parameter.topicId = res.rows[0].id;res.rows.map((item) => {this.parameter.baseId = item.baseId;});// console.log("结果参数", this.parameter);} else {Toast(res.info);}}).catch((err) => {console.log(err);});},

以上第一题题目就成功显示了

接下来是点击“下一题”操作,写了很详细的注释,也包含了走后一题,也就是提交的一些列操作

  // 下一题 并保存当前题目选项数据tonextTimu() {let flag = 0;if (this.theCurrentValue.topicType &&!this.dataArr[this.currentPage].value)//跳转下一页之前,先保存当前题目答案到各题value中flag = 1;switch (this.theCurrentValue.topicType) {case "S":this.$set(this.dataArr[this.currentPage], "value", this.checked);//保存当前题目答案到value中,以便记录每题答案// 单选如果是必填选项,无数据 校验提示if (this.theCurrentValue.isRequired == "1" &&(this.dataArr[this.currentPage].value == null ||this.dataArr[this.currentPage].value == "")) {Toast("该题为必选,请选择!");return;}break;// 多选答案包含两种数据格式,多选为数组value,其他(手动填写)为字符串othervaluecase "M":this.$set(this.dataArr[this.currentPage], "value", this.checked1);// 选择其他时,将其他数据存放到对应tk属性中this.dataArr[this.currentPage].value.map((item, index) => {if (item.title == "其他") {this.$set(this.dataArr[this.currentPage].value[index],"tk",this.otherValue);}});// 如果多选是必填选项,无数据 校验提示if (this.theCurrentValue.isRequired == "1" &&(this.dataArr[this.currentPage].value == null ||this.dataArr[this.currentPage].value.length == 0)) {Toast("请至少选择一项!");return flag;}// 其他必填校验 packRequired==1 选择了其他选项,且其他选项为必填时,校验提示let detectionArray = this.dataArr[this.currentPage].valuefor (let i = 0; i < detectionArray.length; i++) {if (detectionArray[i].packRequired == "1" && detectionArray[i].tk == "") {Toast("请填写!");return flag}}break;case "F":this.$set(this.dataArr[this.currentPage], "value", this.inputval);// 无数据 校验提示if (this.theCurrentValue.isRequired == "1" &&(this.dataArr[this.currentPage].value == null ||this.dataArr[this.currentPage].value.length < 10)) {Toast("请至少输入10个字!");return;}break;case "E":if (!this.dataArr[this.currentPage].value || this.dataArr[this.currentPage].value.length == 0) {this.$set(this.dataArr[this.currentPage],"value",this.attachmentData);this.$set(this.dataArr[this.currentPage], "fileList", this.fileList);}console.log("当前数据", this.dataArr[this.currentPage],this.currentPage,this.dataArr);// 如果多选是必填选项,无数据 校验提示if (this.theCurrentValue.isRequired == "1" &&(this.dataArr[this.currentPage].value == null ||this.dataArr[this.currentPage].value.length == 0)) {Toast("请至少上传一个附件!");return;}break;}// 最后一题时,保存当前题目答案if (this.currentPage + 1 == this.dataArr.length) {console.log("所有题", this.dataArr);// 先处理各题答案let answer = [];this.dataArr.map((item, index) => {// 单选if (item.topicType == "S") {if (item.value) {let t = {};let choiceAnswers = [];t.topicId = item.id;let mult = {id: item.value,tk: item.value.tk == undefined ? "null" : item.value.tk,};choiceAnswers.push(mult);t.choiceAnswers = choiceAnswers;answer.push(t);}console.log("单选", answer);}// 多选if (item.topicType == "M") {let t = {};t.topicId = item.id;let choiceAnswers = [];item.value.map((val, ins) => {let mult = {};mult.id = val.id;mult.tk = val.tk == undefined ? "null" : val.tk;choiceAnswers.push(mult);t.choiceAnswers = choiceAnswers;});answer.push(t);console.log("多选", answer);}// 简答if (item.topicType == "F") {let t = {};t.topicId = item.id;t.packAnswers = item.value;answer.push(t);console.log("简答", answer);}// 上传附件if (item.topicType == "E") {console.log(item.value);let t = {};t.topicId = item.id;if (item.value) {t.attPath = item.value.join(",");} else {t.attPath = "";}answer.push(t);console.log("上传附件", answer);}});console.log("答案", answer);//调用提交函数this.$post("/followup/writeQuestionAnswer", {taskId: this.$route.query.taskId,list: JSON.stringify(answer),}).then((res) => {if (res.result == "success") {console.log(res);// 提交成功跳转结果页面this.$router.push({path: "/question-resuilt",query: {taskId: this.$route.query.taskId,sexFlg: this.$route.query.sex,},});}}).catch((err) => {console.log(err);});return;}this.currentPage++;this.currentPage =this.currentPage >= this.dataArr.length? this.dataArr.length: this.currentPage;//为下一页题目赋值this.theCurrentValue = this.dataArr[this.currentPage];this.topicType = this.theCurrentValue.topicType;// 改变参数topicIdthis.parameter = this.theCurrentValue.id;// 处理多道相同类型题目 数据处理switch (this.theCurrentValue.topicType) {case "S":if (!this.dataArr[this.currentPage].value) {this.$nextTick(() => {this.$refs.radioRef.checked = "";});this.checked = null;} else {this.$nextTick(() => {this.$refs.radioRef.checked =this.dataArr[this.currentPage].value;});}break;case "M":if (this.dataArr[this.currentPage].value == undefined ||this.dataArr[this.currentPage].value.length == 0) {this.$nextTick(() => {this.$refs.multipleChoiceRef.checked1 = [];this.$refs.multipleChoiceRef.othervalue = "";this.$refs.multipleChoiceRef.checkedother = false;});this.checked1 = [];this.otherValue = "";} else {this.$nextTick(() => {//  debuggerthis.$refs.multipleChoiceRef.checked1 =this.dataArr[this.currentPage].value;this.dataArr[this.currentPage].value.map((item, index) => {if (item.title == "其他") {this.$refs.multipleChoiceRef.othervalue =this.dataArr[this.currentPage].value[index].tk;} else {this.$refs.multipleChoiceRef.othervalue = "";}});});}break;case "F":if (!this.dataArr[this.currentPage].value) {this.$nextTick(() => {this.$refs.briefAnswer.inputval =this.dataArr[this.currentPage].value;});this.inputval = null;} else {this.$nextTick(() => {this.$refs.briefAnswer.inputval =this.dataArr[this.currentPage].value;});}break;case "E":if (this.dataArr[this.currentPage].value == undefined ||this.dataArr[this.currentPage].value.length == 0) {this.$nextTick(() => {//  去除图片链接this.$refs.uploadAttachment.uploadUrl = [];// 去除图片显示this.$refs.uploadAttachment.fileList = [];});this.attachmentData = [];this.fileList = [];} else {this.$nextTick(() => {this.$refs.uploadAttachment.uploadUrl =this.dataArr[this.currentPage].value;this.$refs.uploadAttachment.fileList =this.dataArr[this.currentPage].fileList;});}break;}},

“上一题”同样需要先保存当前答案,再赋值前一题的数据,以及答案的复现

// 上一题tolastTimu() {if (this.currentPage <= 0) {return;}if (this.theCurrentValue.topicType &&!this.dataArr[this.currentPage].value)switch (this.theCurrentValue.topicType) {case "S":this.$set(this.dataArr[this.currentPage], "value", this.checked);break;case "M":this.$set(this.dataArr[this.currentPage], "value", this.checked1);// 选择其他时,将其他数据存放到对应tk属性中this.dataArr[this.currentPage].value.map((item, index) => {if (item.title == "其他") {this.$set(this.dataArr[this.currentPage].value[index],"tk",this.otherValue);}});break;case "F":this.$set(this.dataArr[this.currentPage], "value", this.inputval);break;case "E":this.$set(this.dataArr[this.currentPage],"value",this.attachmentData);this.$set(this.dataArr[this.currentPage],"fileList",this.fileList);break;}this.currentPage--;this.currentPage = this.currentPage >= 0 ? this.currentPage : 0;this.theCurrentValue =this.currentPage < 0 ? this.dataArr[0] : this.dataArr[this.currentPage];this.topicType = this.theCurrentValue.topicType;if (this.currentPage < 0) {return;}switch (this.theCurrentValue.topicType) {case "S":this.$nextTick(() => {this.$refs.radioRef.checked = this.dataArr[this.currentPage].value;});break;case "M":this.$nextTick(() => {this.$refs.multipleChoiceRef.checked1 =this.dataArr[this.currentPage].value;// 选择其他时,将其他数据存放到对应tk属性中// 如果有数据if (this.dataArr[this.currentPage].value.length != 0) {this.dataArr[this.currentPage].value.map((item, index) => {if (item.title == "其他") {this.$refs.multipleChoiceRef.othervalue =this.dataArr[this.currentPage].value[index].tk;} else {this.$refs.multipleChoiceRef.othervalue = "";}});} else {this.$refs.multipleChoiceRef.othervalue = "";// 没数据时,清空所有值this.$set(this.dataArr[this.currentPage], "value", "");}});break;case "F":this.$nextTick(() => {this.$refs.briefAnswer.inputval =this.dataArr[this.currentPage].value;});this.attachmentData = this.dataArr[this.currentPage].valuebreak;case "E"://  debuggerthis.$nextTick(() => {this.$refs.uploadAttachment.uploadUrl =this.dataArr[this.currentPage].value;this.$refs.uploadAttachment.fileList =this.dataArr[this.currentPage].fileList;console.log("当前题", this.dataArr[this.currentPage]);});break;}},

下面是一系列的获取子组件的值,也就是那些答案值

   // 获取单选值getvalueEv(val) {this.checked = val;},// 多选数据getMultvalue(val) {if (val) {this.checked1 = val;} else {return;}},// 其他数据单独获取处理getotherVal(otherValue) {this.otherValue = otherValue;},//获取建议数据getrecommendvalue(val) {this.inputval = val;},// 获取附件信息图片链接accessAttachment(uploadUrl) {this.attachmentData = uploadUrl;},// 获取图片列表getfilelist(fileList) {this.fileList = fileList;},

目前测试基本没问题,只是整个过程很繁琐,又更好方案的,期望告知!!!

芜湖~~完结撒花

vue实现移动端问卷调查(适配多道题目多种题型)相关推荐

  1. vue实现PC端分辨率适配

    简单的几步~~~ 这里讲二种方式:1.借助插件实现,2.利用css3媒体查询实现 方法一:下载两个插件 1.安装 lib-flexible 和 px2rem-loader 两个插件 npm i lib ...

  2. vue的PC端和移动端分辨率适配

    使用lib-flexible和px2rem实现移动端和PC端界面适配 注释:lib-flexbles是由阿里团队很早提出解决屏幕分辨率适配的问题.现已不被推荐(因为目前比较主流的适配方案是使用vw和v ...

  3. vue实现移动端适配方案

    vue实现移动端适配步骤如下: 先安装amfe-flexible和postcss-pxtorem: npm install amfe-flexible --save npm install postc ...

  4. Vue.js——PC端和移动端样式适配方案

    此方案整合了断点响应式样式,和移动端样式重分配. 前言 最近在学习Vue的项目架构,查询了很多移动端样式适配,整合了一下我自己的适配方案做一个记录,可能不是最好的,但我自己用着还蛮顺手的~欢迎大家补充 ...

  5. vue做移动端适配最佳解决方案,亲测有效

    最近在做商城的项目,发现有赞的ui非常适合,但有一个问题是有赞的ui用的单位是px,做不了移动端的适配,官网的提供的vw适配方案发现不可行,最后还是决定rem来做适配,上网搜了一下,发现了一套可用方案 ...

  6. 魔方APP项目-01-移动端开发相关概念、移动端自适配、元信息(meta)、开发准备、移动端项目搭建(模拟器调试)、APICloud(APICloud 前端框架,获取服务端API接口)

    一.移动端开发相关概念 1.APP类型 ①.Native APP Native APP又称原生APP,就是我们平时说的手机应用软件. 原生APP 是针对IOS.Android.Windows等不同的手 ...

  7. vue PC+移动端 自适应布局

    之前自己接了个项目 PC+移动端 自动适配显示,因为手机端需要自适应,pc也是需要自适应 项目里 PC用的1920px,移动端用的375px,使用媒体查询适配显示 一.环境 使用lib-flexibl ...

  8. 移动端屏幕适配原理以及方法讲解

    序言: 今天周日,我正坐在黄埔区图书馆,思索着关于移动端屏幕适配的问题.作为一名年纪轻轻的前端马蓉,不,是码农,移动端屏幕适配的方案的帖子没读过100篇吧,也读过几十篇了.可是今天我又在思考这个问题了 ...

  9. Vue 搭建移动端 h5 项目步骤

    Vue 搭建移动端 h5 项目步骤 简介 最近团队里的其他前端小伙伴需要自己搭建移动端 h5 项目,没有整体的思路,于是我就写了这个步骤. 提示:(2022-10-28更新) vue-cli 和vue ...

最新文章

  1. log4j2的核弹漏洞是如何被发现的?
  2. mdb导入SqlServer
  3. Java Web 项目目录规范
  4. java学绘图吗_Java绘图
  5. 微服务接入oauth2_微服务权限终极解决方案,Spring Cloud Gateway+Oauth2实现统一认证和鉴权!...
  6. hdu 4810 Wall Painting
  7. jssdk信息验证失败_阿里云环境中TLS/SSL握手失败的场景分析
  8. .inc文件是什么文件?
  9. 人工智能目标检测模型总结(三)——yolov1模型(2)
  10. Windows的一些网络设置
  11. 办公软件在多屏宽屏上的应用设想
  12. 【MFC开发(7)】编辑框控件Edit Control
  13. 解决序列号不正确无法安装Win2003 SP1
  14. 怎么用大众都懂的语言解释黎曼空间?
  15. pytorch加载VGG16及进行fine-tuning训练
  16. 电脑蓝屏c000021a代码错误
  17. 保姆式RecyclerView下拉刷新、上拉加载更多Kotlin
  18. windows照片查看器解决方案
  19. XTW100高速编程器WIN10驱动安装
  20. 中国抓到了勒索病毒作者!!

热门文章

  1. 干货 | 基于 Python 的信用评分模型实战!
  2. unity Ignis - Interactive Fire(完美模拟:森林火灾、草原火灾、建筑火灾)
  3. 雷柏 v500s 键盘 开箱
  4. 【fastadmin】如何自定义批量操作按钮以及导入excel表格添加多个管理员
  5. 熟悉linux操作系统的使用实验报告,Linux系统的熟悉与使用操作系统实验报告
  6. linux kmalloc原理,kmalloc 函数内幕
  7. CatBoost:如何通过CatBoost作为模型分布式的技术
  8. Windows Live Mail不能发送图片附件的2种解决方法
  9. [CF_GYM101630J]Journey from Petersburg to Moscow
  10. hash,kmp题组所有题解