【开发实战】element常用组件应用例子(富文本,api调用,图片上传,分页查询等)

项目前端使用的是 vue + element 框架为基础, 来缩短开发的流程和时间, 谁用谁知道~!

因为前端整体界面风格参考的是ruoyi的界面, 不过有vue的基础, 代码读起来也基本不会太吃力的

http://www.ruoyi.vip/

以下是项目开发中遇到的问题解决, 以及代码中值得学习的片段

同时也慢慢加入了自己的一点总结反思, 只为变的更强嘻嘻

1. 富文本

rich 编辑使用的是轻量级富文本编辑器 Vue-Quill-Editor

1.1 安装

npm install vue-quill-editor --save

1.2 在 main.js 中将组件引入到全局

// 引入富文本编辑器
import VueQuillEditor from 'vue-quill-editor'
// require styles 富文本编辑器对应的样式
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'

// // 注册富文本编辑器组件为全局组件
Vue.use(VueQuillEditor)

1.3 在 vue 中使用

该例子已经将富文本中图片上传优化为上传到图片服务器上, 原本为 base64 格式存储在字段中

熟悉之后, 如果各个模块使用较多, 可以将富文本封装为一个新的组件 components, 便于复用

代码:

html片段

<el-form-item label="内容" prop="content">
    <div class="edit_container">
        <quill-editor v-model="form.content"
            class="quill-editor ql-editor"
            ref="myQuillEditor"
            :options="editorOption"
            @blur="onEditorBlur($event)"
            @focus="onEditorFocus($event)"
            @change="onEditorChange($event)" />
    </div>
    
	<!-- 图片上传组件辅助-->
    <el-upload
        class="avatar-uploader"
        :action="uploadUrl"
        name="file"
        :show-file-list="false"
        list-type="picture"
        :multiple="false"
        :on-success="quillUploadSuccess"
        :on-error="quillUploadError"
        :before-upload="quillBeforeUpload" />
</el-form-item>

JavaScript片段

data() {
    return {
        uploadUrl: process.env.VUE_APP_BASE_API + "/api/file/upload", //上传路径
        //富文本编辑
      	editorOption: {
        	placeholder: '请在此输入内容...',
        	modules: {
          	imageDrop: true, //开启拖拽,
          	toolbar: {
           	 container: [
              ['bold', 'italic', 'underline', 'strike'],    //加粗,斜体,下划线,删除线
              ['blockquote', 'code-block'],     //引用,代码块

              [{ 'header': 1 }, { 'header': 2 }],       // 标题,键值对的形式;1、2表示字体大小
              [{ 'list': 'ordered'}, { 'list': 'bullet' }],     //列表
              [{ 'script': 'sub'}, { 'script': 'super' }],   // 上下标
              [{ 'indent': '-1'}, { 'indent': '+1' }],     // 缩进
              [{ 'direction': 'rtl' }],             // 文本方向

              [{ 'size': ['small', false, 'large', 'huge'] }], // 字体大小
              [{ 'header': [1, 2, 3, 4, 5, 6, false] }],     //几级标题

              [{ 'color': [] }, { 'background': [] }],     // 字体颜色,字体背景颜色
              [{ 'font': [] }],     //字体
              [{ 'align': [] }],    //对齐方式

              ['clean'],    //清除字体样式
              ['image']    //上传图片、上传视频
            ],
            // container: "#toolbar",
            handlers: {
              image: function(value) {
                if (value) {
                  // 触发input框选择图片文件
                  document.querySelector(".avatar-uploader input").click();
                } else {
                  this.quill.format("image", false);
                }
              },
            }
          }
        },
        theme:'snow',
      },
    }
}
methods: {
    //富文本编辑器---------------
    onEditorReady(editor) {}, // 准备编辑器
    onEditorBlur() {}, // 失去焦点事件
    onEditorFocus(val, editor) {
      // console.log(val); // 富文本获得焦点时的内容
      // editor.enable(false); // 在获取焦点的时候禁用
    }, // 获得焦点事件
    onEditorChange() {}, // 内容改变事件
    saveQuillEditorValue: function(event) {
      alert(this.quillEidtorValue);
    }, //-----------------------
        
    // 富文本图片上传前 ============================================富文本
    quillBeforeUpload() {
      // 显示loading动画
      this.quillUpdateImg = true;
    },
    quillUploadSuccess(res, file) {
      // res为图片服务器返回的数据
      // 获取富文本组件实例
      let quill = this.$refs.myQuillEditor.quill;
      // 如果上传成功
      if (res.code == 200) {
        // 获取光标所在位置
        let length = quill.getSelection().index;
        // 插入图片  res.url为服务器返回的图片地址
        quill.insertEmbed(length, "image", res.data);
        // 调整光标到最后
        quill.setSelection(length + 1);
      } else {
        this.$message.error("图片插入失败");
      }
      // loading动画消失
      this.quillUpdateImg = false;
    },
    // 富文本图片上传失败
    quillUploadError() {
      // loading动画消失
      this.quillUpdateImg = false;
      this.$message.error("图片插入失败");
    }, // ======================================================
}

css片段

p {
    margin: 10px;
}

.ql-container{
    height: 300px;
}

.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
    content: "14px";
}

.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
    content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
    content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
    content: "32px";
}

.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
    content: "文本";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
    content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
    content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
    content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
    content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
    content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
    content: "标题6";
}

.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
    content: "标准字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
    content: "衬线字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
    content: "等宽字体";
}

2. 数据校验

大多数时刻前端都要对用户输入的内容进行判断, 输入是否是合法的, 即数据校验

例如不能输入为空, 手机号必须11位等

复杂的内容校验推荐使用正则表达式判断

<!-- 为表单添加校验规则 -->
<el-form ref="form" :model="form" :rules="rules" label-width="100px">

js 片段

// 表单校验
rules: {
    type: [
    	{ required: true, message: "类型不能为空", trigger: "blur" }
    ],
    unitPrice: [
    	{required: true, message: "价格不能为空", trigger: "blur"},
    	{ pattern: /^[0-9]+([.]{1}[0-9]+){0,1}$/, message: '价格只能为数字或小数', 
         trigger: 'blur' }
	],
	taobaoUrl: [
		{ pattern: /^https{0,1}:\/\/[^\n\r\s]{3,}$/, message: '链接格式错误', 
         trigger: 'blur' }
	],
    // ...
}

3. 图片上传

使用的基础为 element-ui 的上传组件来上传图片

代码:

<el-upload
    :action="uploadUrl"
    list-type="picture-card"
    :class="{hide: hideImageUploadEdit}"
    :on-change="handleEditChange"
    :on-preview="handlePictureCardPreview"
    :before-upload="beforeAvatarUpload"
    :on-success="handleSuccess"
    :on-remove="handleRemove"
    :limit="limit"
    :file-list="picList">
    	<i class="el-icon-plus"></i>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
    	<img width="100%" :src="dialogImageUrl" alt="">
    </el-dialog>

JavaScript片段

// 图片对象数组
picList: [],
limit: 1,
hideImageUploadEdit: false, // 上传限制 隐藏上传按钮
dialogImageUrl: '',
dialogVisible: false,
uploadUrl: process.env.VUE_APP_BASE_API + "/api/file/upload",

    
// 加文件、上传成功和上传失败时都会被调用 --------------------------- 图片上传
handleEditChange(file, fileList) {
    this.hideImageUploadEdit = fileList.length >= this.limit;
    // console.log("this.fileList:", this.fileList);
    // console.log("this.hideUploadEdit:", this.hideImageUploadEdit);
},

// 图片上传成功
handleSuccess(response, file, fileList){
    file.url= response.data;
    this.picList = fileList;
},
// 图片移除事件
handleRemove(file, fileList) {
    //console.log(file, fileList);
    this.picList = fileList;
    this.hideImageUploadEdit = fileList.length >= this.limit;
},
// 点击图片事件
handlePictureCardPreview(file) {
    this.dialogImageUrl = file.url;
    this.dialogVisible = true;
},
//上传前校验图片
beforeAvatarUpload(file) {
    const isJPG = file.type === "image/jpeg" || file.type === "image/png";
    // const isLt10M = file.size / 1024 / 1024 < 10;

    if (!isJPG) {
    	this.$message.error('上传图片只能是 JPG 或 PNG 格式!');
    }
    /*if (!isLt10M) {
    	this.$message.error('上传图片大小不能超过 10MB!');
    }*/
    return isJPG ;
}, // ------------------------------------------------------------------

css片段

这里是为了添加图片的上传限制, 超过指定数量隐藏 +

.hide .el-upload--picture-card {
	display: none;
}

.el-upload-list__item {
	transition: none !important;
}

4. select 选择器

<el-select v-model="form.type" placeholder="请选择类型">
	<el-option label="上方金刚区" value="1" />
	<el-option label="下方广告区" value="2" />
</el-select>

<!-- 可搜索 可清空 -->
<el-select v-model="form.productId" placeholder="请选择关联商品" filterable clearable>
    <el-option
         v-for="item in mallProductList"
         :key="item.id"
         :label="item.name"
         :value="item.id" />
</el-select>

字典数据获取

ruoyi 框架提供灵活的字典功能, 例如保存性别键值

男 1; 女 0

sortOptions: [], // 指标类别

// 获取Options
getSort(){
	this.getDicts("t_review_item_type").then(response => {
        this.sortOptions = response.data;
        console.log(this.sortOptions)
    });
},

5. api 调用

request 方法

前端index调用封装的 js 方法 — request 方法统一放在 src/api/(大模块名)/xxx.js

优点: 可以传若干个自定义的参数

import request from '@/utils/request'

// 后端采用方法体接收 `@RequestBody`
// 资讯状态修改
// 根据id修改数据的状态(state)
export function changeNewStatus(id, state) {
  const data = {
    id,
    state
  };
  return request({
    url: '/module/waterBeautyEconomy/changeStatus',
    method: 'put',
    data: data
  })
}

switch 启用

touch 开关, 弹出确认框(包含确认和取消)

点击确认, 调用接口成功后, 弹出消息 “启用成功”

点击取消, 则复原开关状态

代码:

html 片段

<el-switch 
	v-model="scope.row.status" 
	:active-value="1" 
	:inactive-value="0" 
	@change="handleStatusChange(scope.row)" />

switch 开关使用的是 element 组件

js 片段

// 状态修改
handleStatusChange(row) {
    let text = row.status == 1 ? "启用" : "停用";
    this.$confirm(
        '确认要"' + text + '" "' + row.questionStem + '" 试题吗?',
        "警告",
        {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning",
        }
    )
        .then(function () {
        return changeNewStatus(row.id, row.status);
    })
        .then(() => {
        this.msgSuccess(text + "成功");
    })
        .catch(function () {
        row.status = row.status == 0 ? 1 : 0;
    });
},

list 获取

listWaterBeautyEconomy 这里是调用了/api 下的 js 方法

/** 查询水美经济列表 */
getList() {
    this.loading = true;
    listWaterBeautyEconomy(this.queryParams).then(response => {
        this.waterBeautyEconomyList = response.rows;
        this.total = response.total;
        this.loading = false;
    });
},

弹出确认框

先为按钮添加特定事件 ->

点击特定按钮弹出 confirm 框, 点击确定则调用接口

js 片段

/** 退款申请 */
handlePut(row) {
    const id = row.id;
    // console.log(id);
    this.$confirm('是否确认退款申请, 编号:' + row.number , "退款申请", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "info"
    }).then(function() {
    	return refund(id);
    }).then(() => {
        this.getList();
        this.msgSuccess("退款申请成功");
    });
},

add update 方法

reqeust 片段

// 新增试题
export function addQuestion(data) {
  return request({
    url: '/driver/question',
    method: 'post',
    data: data
  })
}

// 修改试题
export function updateQuestion(data) {
  return request({
    url: '/driver/question',
    method: 'put',
    data: data
  })
}

js 片段

/** 提交按钮 */
submitForm: function() {
    this.$refs["form"].validate(valid => {
        if (valid) {
            if (this.form.id != undefined) {
                updateQuestion(this.form).then(response => {
                    if (response.code === 200) {
                        this.msgSuccess("修改成功");
                        this.open = false;
                        this.getList();
                    }
                });
            } else {
            	addQuestion(this.form).then(response => {
                    if (response.code === 200) {
                        this.msgSuccess("新增成功");
                        this.open = false;
                        this.getList();
                    }
                });
            }
        } // if(v..)
    });
},

delete 方法

request 片段

// Rest风格
// 删除考评任务
export function delQuarterlyReviewGroup(id) {
  return request({
    url: '/module/quarterlyReviewGroup/' + id,
    method: 'delete'
  })
}

js 片段

/** 删除按钮操作 */
handleDelete(row) {
    const ids = row.id || this.ids;
    this.$confirm('是否确认删除试题编号为"' + ids + '"的数据项?', "警告", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
    }).then(function() {
        return delQuestion(ids);
    }).then(() => {
        this.getList();
        this.msgSuccess("删除成功");
    }).catch(function() {});
},

js 片段

updateQuarterlyReviewGroup(this.form).then(response => {
	if (response.code === 200) {
		this.msgSuccess("修改成功");
		this.open = false;
		this.getList();
	}
});

6. 查询参数

list 页面可以提供查询筛选的功能

参数:

// 查询参数
queryParams: {
    orderByColumn: "create_time",
    isAsc: "desc",
    pageNum: 1,
    pageSize: 10,
    title: undefined,
},

7. Table 表格

二级 table

例如点击考评员, 进入新的 table 页面, 选择是哪个考评员

代码:

html 片段

<!-- 选择考评人对话框 -->
<el-dialog title="选择考评员" :visible.sync="examinerOpen" width="900px" append-to-body>

    <el-form :model="examinerQueryParams" ref="examinerQueryForm" 
             :inline="true" label-width="68px">
        <el-form-item label="状态" prop="state">
            <el-select v-model="examinerQueryParams.state" placeholder="请选择状态">
            <el-option value="leisure" label="空闲"/>
            <el-option value="appoint" label="已指定"/>
            <el-option value="busy" label="考评中"/>
            </el-select>
            <!--<el-input
            v-model="queryParams.number"
            placeholder="请输入编号"
            clearable
            size="small"
            @keyup.enter.native="handleQuery"
            />-->
        </el-form-item>
        <el-form-item>
            <el-button type="primary" icon="el-icon-search" size="mini" 
                       @click="examinerHandleQuery">搜索</el-button>
            <el-button icon="el-icon-refresh" size="mini" 
                       @click="examinerResetQuery">重置</el-button>
        </el-form-item>
    </el-form>

    <el-table v-loading="examinerLoading" :data="examinerList" 
              @selection-change="examinerHandleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <!--<el-table-column label="id" align="center" prop="id" />-->
        <el-table-column label="编号" align="center" prop="number" />
        <el-table-column label="派往村" align="center" prop="ruralId">
            <template slot-scope="scope">
                <span v-if="scope.row.ruralId==null || scope.row.ruralId===''">-</span>
                <span v-for="rural in ruralList">
                <span v-if="rural.id ===scope.row.ruralId">{{rural.villageName}}</span>
                </span>
            </template>
        </el-table-column>
        <el-table-column label="姓名" align="center" prop="name" />
        <el-table-column label="所在县市" align="center" prop="addressId" >
            <template slot-scope="scope">
                <span v-if="scope.row.addressId==null || scope.row.addressId===''">-</span>
                <span v-for="rural in ruralList">
                <span v-if="rural.id ===scope.row.addressId">
                    {{rural.cityName}}{{rural.countyName}}</span>
                </span>
            </template>
        </el-table-column>
        <el-table-column label="联系方式" align="center" prop="phone" >
            <template slot-scope="scope">
            	<span v-if="scope.row.phone==null || scope.row.phone===''">-</span>
            	<span v-else>{{scope.row.phone}}</span>
            </template>
        </el-table-column>
        <el-table-column label="状态" align="center" prop="state" >
            <template slot-scope="scope">
                <span style="color:green" v-if="scope.row.state==='leisure'">空闲</span>
                <span style="color:red" v-else-if="scope.row.state==='appoint'">
                    已指定</span>
                <span style="color:red" v-else-if="scope.row.state==='busy'">考评中</span>
                <span v-else>-</span>
            </template>
        </el-table-column>
    </el-table>
    
    <pagination
        v-show="examinerTotal>0"
        :total="examinerTotal"
        :page.sync="examinerQueryParams.pageNum"
        :limit.sync="examinerQueryParams.pageSize"
        @pagination="getExaminerList"/>
    
    <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="examinerSubmitForm">确 定</el-button>
        <el-button @click="examinerCancel">取 消</el-button>
    </div>
    
</el-dialog>

data 数据

export default {
    data() {
        // 弹出考评人选择
		examinerOpen: false,
        examinerIds: [],
        // 总条数
        examinerTotal: 0,
        examinerLoading: true,
        // 查询参数
      	examinerQueryParams: {
        	orderByColumn: "create_time",
        	isAsc: "desc",
        	pageNum: 1,
        	pageSize: 10,
        	state: undefined,
      	},
    }
}

js 片段

// 选择考评人按钮
examinerHandle(){
    this.examinerOpen = true;
    //this.resetForm("queryForm");
},

// 多选框选中 触发事件
examinerHandleSelectionChange(selection) {
    if (selection.length > 1) this.msgError("只能指派一个考评人");
    this.examinerIds = selection.map(item => item.id);
},
    
// 确认按钮操作 
examinerSubmitForm(){
    if (this.examinerIds.length > 1) {
        this.msgError("只能指派一个考评人");
        return;
    }
    this.form.examinerId = this.examinerIds[0];
    this.examinerOpen = false;
    this.examinerResetQuery();
    console.log(this.form);
},
    
// 取消按钮操作 
examinerCancel(){
    this.examinerOpen = false;
    // this.reset(); // 重置form this.resetForm("form");
},
    
/** 搜索按钮操作 */
examinerHandleQuery() {
	this.examinerQueryParams.pageNum = 1;
	this.getExaminerList();
},
    
/** 重置按钮操作 */
examinerResetQuery() {
    this.resetForm("examinerQueryForm"); // 重置查询表单
    this.examinerHandleQuery(); // 搜索一次
},

序号显示

在数据前的第一列添加一个序号显示 1 2 3 …

<el-table-column type="index" label="序号" align="center" :index="indexMethod"/>

例如第一页序号为 1-10, 第二页序号为 11-20

/** 连续序号 */
indexMethod(index) {
	return (index+1) + (this.queryParams.pageNum-1)*this.queryParams.pageSize;
},
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值