本博文记录了在vue项目开发中的一些经验,具体包含:class动态绑定、子页面刷新、注入函数到子页面、数据加载效果、单击后编辑、文件上传、数据分页、表单提交等的使用记录。
1、class动态绑定
根据变量的值绑定不同的class样式,这里ftype的值可为full_label、zero_label、has_label三种class样式名
<div class="folderImg" :class="ftype" @click="to_url('showimglist',fd.name)"><i class="el-icon-folder-opened avatar-uploader-icon"></i></div>
对应的class设置有
.full_label {background-image: url(../../assets/full_label.png);background-repeat:no-repeat;background-size:100% 100%;-moz-background-size:100% 100%;
}.zero_label {background-image: url(../../assets/zero_label.png);background-repeat:no-repeat;background-size:100% 100%;-moz-background-size:100% 100%;
}.has_label {background-image: url(../../assets/has_label.png);background-repeat:no-repeat;background-size:100% 100%;-moz-background-size:100% 100%;
}
2、子页面刷新 | 注入函数到子页面
通过v-if的方式设置子页面不可见,然后在this.$nextTick设置子页面可见,从而实现对子页面的刷新。然后将封装为reload函数,并注入函数到子页面,在子页面调用即可。
具体参考:https://www.jb51.net/article/260561.htm
<template><div id="app"><!--img src="./assets/logo.png"--><router-view v-if="isRouterAlive"></router-view></div>
</template>
<script>
import axios from 'axios'
export default {name: 'App',provide () { //设置被注入到子页面的函数return {reload: this.reload,}},data () {return {isRouterAlive: true,}},methods: {reload () {this.isRouterAlive = falsethis.$nextTick(function () {this.isRouterAlive = true})},}
}
</script>
子页面的js中设置inject即可在子页面刷新内容
//子页面<script> export default {name: 'showanalysis',inject: ['reload'], //接收父页面注入的内容}</script>
3、数据加载效果
用于服务器返回结果中的过程界面(当前端调用后台接口时触发该效果,获取到结果后取消显示)
具体参考 https://element.faas.ele.me/#/zh-CN/component/loading#loading-jia-zai
具体用例如下,在元素中添加v-loading属性绑定变量loading,默认为false不显示效果;当触发其他耗时操作时,修改loading为true,显示加载中效果;当操作完成时,修改loading为false。
<template><div class="demo-image"v-loading="loading"element-loading-text="等待服务器处理中"element-loading-spinner="el-icon-loading"element-loading-background="rgba(0, 0, 0, 0.8)"></div>
</template><script>export default {name: 'showdatafolder',data() {return {loading: false,}},}
}
</script>
4、宽高百分比
使用vh,vw来控制元素相对于屏幕的宽高百分比。vh和wh是视口单位,是相对长度单位。wh是相对于视口的宽度,“1vw”等于视口宽度的“1%”;而vh是相对于视口的高度,“1vh”等于视口高度的“1%”
具体参考:https://www.php.cn/faq/489349.html
5、单击后编辑
text类控件在单击后转换为input控件,在失去焦点后又变换text类空间。
以下为el-button控件与el-input控件的结合,当点击el-button后,与之对应的el-input展示,当el-input失去焦点后又显示为el-button。
<el-inputclass="input-new-tag"v-if="inputVisible"v-model="inputValue"ref="saveTagInput" #为控件取了一个名字size="small"@keyup.enter.native="handleInputConfirm"@blur="handleInputConfirm"
>
</el-input>
<el-button v-else class="button-new-tag" size="small" @click="showInput">+ New Tag</el-button><script>export default {data() {return {dynamicTags: ['标签一', '标签二', '标签三'],inputVisible: false,inputValue: ''};},methods: {showInput() {this.inputVisible = true;this.$nextTick(_ => {this.$refs.saveTagInput.$refs.input.focus();//设置指定控件获取输入焦点});},handleInputConfirm() {let inputValue = this.inputValue;if (inputValue) {this.dynamicTags.push(inputValue);}this.inputVisible = false;this.inputValue = '';}}}
</script>
关键解析:
1、通过v-if='inputVisible' , v-else
,绑定变量inputVisible设置el-button与与el-input的显示切换
2、为el-input控件设置ref,既为控件取名字。当点击button时,触发showInput事件
,设置el-input可见,并获取输入焦点
3、通过设置el-input的@blur与@keyup.enter.native
属性,对输入完成后的操作进行监听,并设置inputVisible = false
输入框不可见,inputValue = ''
输入框的值为空`
代码参考自:https://element.faas.ele.me/#/zh-CN/component/tag
单击前效果
控件输入时效果
6、文件上传
这里仅实现最简单的文件上传方式,多文件上传(实质为多次调用文件上传接口)请参考 https://element.faas.ele.me/#/zh-CN/component/upload
html页面
设置action为null,主要是在:before-upload
所绑定的函数中实现文件上传
<el-upload class="upload-demo" drag action="null" :before-upload="beforeAvatarUpload"><i class="el-icon-upload"></i><div class="el-upload__text">将pt文件拖到此处,或<em>点击上传</em></div><div class="el-upload__tip" slot="tip">只能上传pt文件,且不超过500kb</div></el-upload>
js实现
在beforeAvatarUpload函数中,可以对文件后缀、文件size进行判断,最后使用axios创建post请求将文件提交到后端
beforeAvatarUpload(file) {import axios from 'axios'const isAllow = file.name.indexOf('.pt') > 0 || file.name.indexOf('.PT') > 0;const isLt200M = file.size / 1024 / 1024 / 200;if (!isAllow) {this.$message.error("只允许上传pt文件!");return false} else if (!isLt200M) {this.$message.error('上传模型大小不能超过 200MB!');return false} else {//手动进行文件上传let formData = new FormData();formData.append("file", file);axios({url: "/api/uploader",//上传文件接口method: "post",headers: {"Content-Type": "multipart/form-data",},data: formData,}).then((res) => {this.$message({title: '结果提示',message: res.data.msg,type: 'success'});this.reload();});}return false},
后端代码
后端基于flask实现
@app.route('/uploader',methods=['GET','POST'])
def uploader():if request.method == 'POST':f = request.files['file']#跟表单里file中的name要一样spath=os.path.join(runDir, f.filename)print(spath)f.save(spath)json={'code':0,'msg':'文件上传成功!'}return jsonify(json) else:return 'please uplaod file use post method!'
更多内容参考 https://element.faas.ele.me/#/zh-CN/component/upload
7、数据分页
在element-ui中详细介绍了分页控件的用法,但并未配合任何具体案例介绍。https://element.faas.ele.me/#/zh-CN/component/pagination
html页面
第一个部件为grid-content,里面v-for循环对应变量img_list,用于显示分页的具体内容
第二部分为el-pagination控件,对应具体的分页控件。可以通过修改layout对应的text,实现对分页部件内容的位置控制
<template><div class="demo-image"><el-row><div class="grid-content"><div class="block" v-for="d in img_list" :key="d"><div class="demo-image__preview"><el-image style="width: 200px; height: 200px" :src="d" :preview-src-list="img_list"></el-image><div class="bottom clearfix"><el-button type="text" class="button" @click="to_url('labelimg',{'currentImage':d})">标注</el-button><el-button type="text" class="button" @click="delete_img(d)">删除</el-button></div></div></div></div></el-row><el-row><el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="0":page-sizes="[6, 8, 10, 12, 15, 18]" :page-size="default_page_size"layout="total, sizes, prev, pager, next, jumper" :total="all_img_list.length"></el-pagination></el-row></div>
</template>
js实现
主要涉及的变量有all_img_list | 所有的数据、img_list | 当前分页的数据、default_page_size | 每一页的数据量、default_page | 当前页。
在页面初始化的时候,既mounted函数中获取全部数据设置到all_img_list中,并根据default_page_size、default_page截取当前页内容设置到img_list中。
<script>
import axios from 'axios'
export default {name: 'showimglist',data() {return {all_img_list: [],img_list: [],default_page_size: 10,default_page: 1,}},mounted() {if(this.$route.query.dname){localStorage.setItem('dname', this.$route.query.dname);}let dname = localStorage.getItem('dname');//this.$route.params.dname;this.dname=dname;if (dname) {let formData = new FormData();formData.append("dname", dname);axios({url: '/api/datamanage_get_imglist',//上传文件接口method: "post",headers: {"Content-Type": "multipart/form-data",},data: formData,}).then((res) => {this.all_img_list = res.data;this.img_list = this.all_img_list.slice(0, this.default_page_size)});}},methods: {handleSizeChange(val) {this.default_page_size = val;this.img_list = this.all_img_list.slice((this.default_page - 1) * this.default_page_size, this.default_page * this.default_page_size);},handleCurrentChange(val) {this.default_page = valthis.img_list = this.all_img_list.slice((this.default_page - 1) * this.default_page_size, this.default_page * this.default_page_size);},}
}
</script>
以上代码中,handleSizeChange用于监听分页数量的改变,handleCurrentChange用于检测页码数的改变
后端实现
这里的分页本质上与后端没有任何关系,每次分页时并未向后端请求对应页码的数据,仅在已有数据中进行截取。
当总数据较多时,可以在handleSizeChange与handleCurrentChange中实时从后端获取数据。
最终实现的页面效果如下
8、表单提交
表单实现
以下表单所绑定的为json对象:model="ruleForm"
,故此v-model="ruleForm.name"
其el-form-item所绑定的为ruleForm.name,同时还:rules="rules"
绑定了验证规则rules,ref="ruleForm"
表单被命名为ruleForm。
由submitForm事件提交表单
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" style="padding: 30px;width:400px;background-color: bisque;" label-width="100px" class="demo-ruleForm"><el-form-item label="用户名" prop="name"><el-input v-model="ruleForm.name"></el-input></el-form-item><el-form-item label="密码" prop="pwd"><el-input type="password" v-model="ruleForm.pwd"></el-input></el-form-item><el-form-item><el-button type="primary" @click="submitForm('ruleForm')">立即登录</el-button><el-button @click="resetForm('ruleForm')">重置</el-button></el-form-item></el-form>
表单验证及提交
ruleForm对象为表单所绑定的数据模型
rules为表单具体字段的验证规则,针对每一个字段都可以设置多条规则
submitForm函数实现表单的验证及提交
export default {name: 'login',data() {return {ruleForm: {name: '',pwd: '',},rules: {name: [{ required: true, message: '请输入用户名', trigger: 'blur' },{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }],pwd: [{ required: true, message: '请输入密码', trigger: 'blur' },{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }],}};},methods: {submitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {//表单验证成功,进入后台主页this.$router.push({name:'mainframe'});} else {console.log('error submit!!');return false;}});},resetForm(formName) {this.$refs[formName].resetFields();}}}