简介
Vue单元组件渲染提供了三种方式在表格单元格中渲染自定义 Vue 组件:
addColumnVueRemote:从远程 URL 加载 Vue 组件addColumnVueRender:直接使用 Vue 模板字符串渲染addColumnVue:从本地文件路径加载 Vue 模板
这些方法让你可以在表格单元格中实现复杂的交互逻辑和自定义展示效果。
用法示例
addColumnVueRemote - 远程组件加载
use plugin\xbCode\builder\Builder;
// 基础用法
Builder::crud(function($builder) {
// 从远程URL加载Vue组件
$builder->addColumnVueRemote('custom', '自定义', '/api/vue/component');
});
// 使用回调函数配置
Builder::crud(function($builder) {
$builder->addColumnVueRemote('action', '操作', '/api/vue/action', function($component) {
$component->width(150);
$component->align('center');
$component->vAlign('middle');
});
});
// 使用数组方式配置
Builder::crud(function($builder) {
$builder->addColumnVueRemote('status_btn', '状态', '/api/vue/status', [
'width' => 120,
'align' => 'center',
'fixed' => 'right'
]);
});远程接口返回示例:
{
"status": 0,
"msg": "success",
"data": {
"component": "<template><div>{{ props.row.title }}</div></template>"
}
}addColumnVueRender - 模板字符串渲染
use plugin\xbCode\builder\Builder;
// 基础用法 - 简单模板
Builder::crud(function($builder) {
$template = '<template><div class="custom-cell">{{ props.row.title }}</div></template>';
$builder->addColumnVueRender('title', '标题', $template);
});
// 复杂模板示例
Builder::crud(function($builder) {
$template = <<<VUE
<template>
<div class="action-buttons">
<el-button size="small" type="primary" @click="handleEdit">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete">删除</el-button>
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue';
const props = defineProps(['row', 'index']);
const emit = defineEmits(['refresh']);
const handleEdit = () => {
console.log('编辑', props.row.id);
};
const handleDelete = () => {
console.log('删除', props.row.id);
emit('refresh');
};
</script>
<style scoped>
.action-buttons {
display: flex;
gap: 8px;
}
</style>
VUE;
$builder->addColumnVueRender('actions', '操作', $template, function($component) {
$component->width(200);
$component->align('center');
});
});
// 使用数组配置
Builder::crud(function($builder) {
$template = '<template><span :class="statusClass">{{ statusText }}</span></template>';
$builder->addColumnVueRender('status', '状态', $template, [
'width' => 100,
'align' => 'center',
'vAlign' => 'middle'
]);
});
addColumnVue - 本地文件加载
use plugin\xbCode\builder\Builder;
// 基础用法
Builder::crud(function($builder) {
// 从本地文件加载Vue模板
$path = base_path('plugin/xbCode/public/vue/custom-cell.vue');
$builder->addColumnVue('custom', '自定义列', $path);
});
// 使用回调函数配置
Builder::crud(function($builder) {
$path = base_path('plugin/xbCode/public/vue/action-buttons.vue');
$builder->addColumnVue('actions', '操作', $path, function($component) {
$component->width(180);
$component->align('center');
$component->fixed('right');
});
});
// 使用数组方式配置
Builder::crud(function($builder) {
$path = base_path('plugin/xbCode/public/vue/status-tag.vue');
$builder->addColumnVue('status', '状态', $path, [
'width' => 100,
'align' => 'center',
'vAlign' => 'middle'
]);
});
本地Vue文件示例(custom-cell.vue):
<template>
<div class="custom-cell">
<el-tag :type="getTagType(props.row.status)">
{{ props.row.status_text }}
</el-tag>
</div>
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps(['row', 'index', 'column']);
const getTagType = (status) => {
const types = {
1: 'success',
0: 'danger',
2: 'warning'
};
return types[status] || 'info';
};
</script>
<style scoped>
.custom-cell {
padding: 4px 0;
}
</style>
addColumnVueRemote 参数
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| name | string | 必填 | 字段名称,对应数据库字段 |
| label | string | 必填 | 列标题,显示在表格头部 |
| url | string | 必填 | 远程组件 URL 地址,接口需返回 Vue 组件模板 |
| option | callable|array | [] | 配置选项,可以是回调函数或数组 |
addColumnVueRender 参数
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| name | string | 必填 | 字段名称,对应数据库字段 |
| label | string | 必填 | 列标题,显示在表格头部 |
| template | string | 必填 | Vue 组件模板字符串(完整的 .vue 单文件内容) |
| option | callable|array | [] | 配置选项,可以是回调函数或数组 |
addColumnVue 参数
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| name | string | 必填 | 字段名称,对应数据库字段 |
| label | string | 必填 | 列标题,显示在表格头部 |
| path | string | 必填 | Vue 模板文件的绝对路径 |
| option | callable|array | [] | 配置选项,可以是回调函数或数组 |
组件属性
所有 Vue 单元组件都继承自 TableColumn,支持以下属性:
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| width | int|string | - | 列宽度 |
| minWidth | int|string | - | 最小列宽度 |
| align | string | - | 水平对齐方式:'left'、'right'、'center' |
| vAlign | string | - | 垂直对齐方式:'top'、'middle'、'bottom' |
| fixed | string | - | 列固定位置:'left'、'right' |
| style | array | - | 单元格自定义样式 |
| innerStyle | array | - | 单元格内部组件自定义样式 |
| remark | string | - | 提示信息 |
| sortable | bool | false | 是否可排序 |
Vue组件内可用属性
在自定义 Vue 组件中,可以通过 props 访问以下数据:
const props = defineProps({
row: Object, // 当前行的完整数据
index: Number, // 当前行索引
column: Object, // 当前列配置
data: Array // 整个表格数据(可选)
});
访问示例:
<template>
<div>
<!-- 访问当前行数据 -->
<span>{{ props.row.id }}</span>
<span>{{ props.row.title }}</span>
<!-- 访问行索引 -->
<span>第 {{ props.index + 1 }} 行</span>
<!-- 访问列配置 -->
<span>{{ props.column.label }}</span>
</div>
</template>
使用场景
addColumnVueRemote 适用场景
- 需要动态加载不同组件的场景
- 组件需要根据权限或条件动态变化
- 组件需要频繁更新而不重新部署
- 多个页面共享相同的远程组件
addColumnVueRender 适用场景
- 组件逻辑相对简单
- 需要快速开发和调试
- 组件代码需要动态生成
- 不希望创建额外的文件
addColumnVue 适用场景
- 组件逻辑复杂,需要独立文件管理
- 需要 IDE 的语法提示和高亮
- 组件需要版本控制
- 团队协作开发,代码复用性高
注意事项
addColumnVueRemote
- 远程 URL 必须返回有效的 Vue 组件模板
- 接口响应格式需符合系统规范
- 建议添加缓存机制以提升性能
- 远程加载可能存在网络延迟
addColumnVueRender
- template 参数不能为空
- 模板必须是完整的 Vue 单文件组件格式
- 可以包含
<template>、<script setup>和<style>标签 - 注意处理字符串中的引号转义
addColumnVue
- path 参数必须是绝对路径
- 文件必须存在,否则会抛出异常
- 建议使用
base_path()或plugin_path()辅助函数 - 文件内容必须是有效的 Vue 单文件组件
- 推荐文件扩展名为
.vue
通用注意事项
- Vue 组件内可以使用 Element Plus 等 UI 组件库
- 组件内的方法和事件需要按照 Vue 3 Composition API 规范编写
- 建议使用
<script setup>语法糖,代码更简洁 - 样式建议使用
scoped作用域,避免污染全局样式 - 复杂交互建议通过事件通知外部刷新数据
完整示例
示例1:订单状态展示
Builder::crud(function($builder) {
$template = <<<VUE
<template>
<div class="order-status">
<el-tag :type="tagType" size="small">
{{ statusText }}
</el-tag>
<el-button
v-if="canOperate"
size="small"
text
@click="handleOperation"
>
操作
</el-button>
</div>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps(['row']);
const statusMap = {
1: { text: '待支付', type: 'warning' },
2: { text: '已支付', type: 'success' },
3: { text: '已取消', type: 'info' },
4: { text: '已退款', type: 'danger' }
};
const statusText = computed(() => {
return statusMap[props.row.status]?.text || '未知';
});
const tagType = computed(() => {
return statusMap[props.row.status]?.type || 'info';
});
const canOperate = computed(() => {
return props.row.status === 1;
});
const handleOperation = () => {
console.log('操作订单', props.row.id);
};
</script>
<style scoped>
.order-status {
display: flex;
align-items: center;
gap: 8px;
}
</style>
VUE;
$builder->addColumnVueRender('status', '订单状态', $template, [
'width' => 150,
'align' => 'center'
]);
});
示例2:评分展示
Builder::crud(function($builder) {
$path = base_path('plugin/xbCode/public/vue/rating-display.vue');
$builder->addColumnVue('rating', '评分', $path, function($component) {
$component->width(150);
$component->align('center');
});
});
rating-display.vue 文件内容:
<template>
<div class="rating-display">
<el-rate
v-model="rating"
disabled
show-score
text-color="#ff9900"
/>
</div>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps(['row']);
const rating = computed(() => {
return parseFloat(props.row.rating) || 0;
});
</script>
<style scoped>
.rating-display {
display: flex;
justify-content: center;
align-items: center;
}
</style>
示例3:远程加载动态按钮组
Builder::crud(function($builder) {
$builder->addColumnVueRemote('operations', '操作', '/api/admin/vue/operations', [
'width' => 200,
'align' => 'center',
'fixed' => 'right'
]);
});
后端接口实现示例:
public function operations()
{
$template = <<<VUE
<template>
<div class="operation-buttons">
<el-button
v-for="btn in buttons"
:key="btn.name"
:type="btn.type"
size="small"
@click="handleClick(btn)"
>
{{ btn.label }}
</el-button>
</div>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps(['row']);
const buttons = computed(() => {
const btns = [];
if (props.row.can_edit) {
btns.push({ name: 'edit', label: '编辑', type: 'primary' });
}
if (props.row.can_delete) {
btns.push({ name: 'delete', label: '删除', type: 'danger' });
}
return btns;
});
const handleClick = (btn) => {
console.log(btn.name, props.row.id);
};
</script>
<style scoped>
.operation-buttons {
display: flex;
gap: 8px;
justify-content: center;
}
</style>
VUE;
return json(['status' => 0, 'data' => ['component' => $template]]);
}
方法对比
| 特性 | addColumnVueRemote | addColumnVueRender | addColumnVue |
|---|---|---|---|
| 加载方式 | 远程接口 | 字符串模板 | 本地文件 |
| 灵活性 | 高 | 中 | 中 |
| 性能 | 低(网络请求) | 高 | 高 |
| 维护性 | 中 | 低 | 高 |
| IDE支持 | 无 | 无 | 有 |
| 适用场景 | 动态组件 | 简单逻辑 | 复杂逻辑 |
| 推荐指数 | ★★★☆☆ | ★★★★☆ | ★★★★★ |