npm install -g @vue/cli
查看@vue/cli
版本,vue -V
。
vue create antd-demo
npm install ant-design-vue@next --save
import { createApp } from 'vue'
import App from './App.vue'
import Antd from "ant-design-vue";
import "ant-design-vue/dist/antd.css";
createApp(App).use(Antd).mount('#app')
<template>
<a-table :dataSource="dataSource" :columns="columns" />
</template>
<script>
export default {
name:"Helloworld",
setup() {
return {
dataSource: [
{
key: '1',
name: '胡彦斌',
age: 32,
address: '西湖区湖底公园1号',
},
{
key: '2',
name: '胡彦祖',
age: 42,
address: '西湖区湖底公园1号',
},
],
columns: [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
},
],
};
},
};
</script>
:columns="columns"
,columns
是一个数组,用于指定列头
dataIndex
值依次是:name
、age
和address
,与dataSource
每项的name
、age
和address
对应。title
,dataIndex
值对应的列头名称
name
,对应的列头名称是姓名
age
,对应的列头名称是年龄
address
,对应的列头名称是地址
key
,Vue需要的key,如果已经设置了唯一的dataIndex
,可以忽略这个属性:dataSource=dataSource
,指定数据源
dataSource
是一个数组name
、age
和address
,与columns
里dataIndex
的值:name
、age
和address
相对应<template>
<a-table :columns="columns" :data-source="data">
<template #name="{ text }">
<a>{{ text }}</a>
</template>
<template #customTitle>
<span>
<smile-outlined />
Name
</span>
</template>
<template #tags="{ text: tags }">
<span>
<a-tag
v-for="tag in tags"
:key="tag"
:color="tag === 'loser' ? 'volcano' : tag.length > 5 ? 'geekblue' : 'green'"
>
{{ tag.toUpperCase() }}
</a-tag>
</span>
</template>
<template #action="{ record }">
<span>
<a>Invite 一 {{ record.name }}</a>
<a-divider type="vertical" />
<a>Delete</a>
<a-divider type="vertical" />
<a class="ant-dropdown-link">
More actions
<down-outlined />
</a>
</span>
</template>
</a-table>
</template>
<script lang="ts">
import { SmileOutlined, DownOutlined } from '@ant-design/icons-vue';
import { defineComponent } from 'vue';
const columns = [
{
dataIndex: 'name',
key: 'name',
slots: { title: 'customTitle', customRender: 'name' },
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
{
title: 'Tags',
key: 'tags',
dataIndex: 'tags',
slots: { customRender: 'tags' },
},
{
title: 'Action',
key: 'action',
slots: { customRender: 'action' },
},
];
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
tags: ['nice', 'developer'],
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
tags: ['loser'],
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
tags: ['cool', 'teacher'],
},
];
export default defineComponent({
setup() {
return {
data,
columns,
};
},
components: {
SmileOutlined,
DownOutlined,
},
});
</script>
注意哈,ant-design-vue Table里:data-source与:dataSource是等效的。
要使用slots
自定义样式,就有必要了解下Vue里的$slots
和Table组件的源码。
插槽内容可以在this.$slots
中看到,举个例子。
base-layout
<template>
<header>
<slot name="header"></slot>
</header>
<main>
<slot name="default"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</template>
<script>
export default {
name:"base-layout"
}
</script>
App.vue
<template>
<BaseLayout>
<template #header>
<p>Here is part one</p>
</template>
<template #default>
<p>Here is part two</p>
</template>
<template #footer>
<p>Here is part three</p>
</template>
</BaseLayout>
</template>
<script>
import BaseLayout from "./components/base-layout.vue";
export default {
name: 'App',
components: {
BaseLayout
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
main.js
import { createApp } from 'vue'
import App from './App.vue'
import Antd from "ant-design-vue";
import "ant-design-vue/dist/antd.css";
createApp(App).use(Antd).mount('#app');
现在我们修改base-layout.vue
,使用this.$slots
来访问插槽内容。
<template>
<header>
<slot name="header"></slot>
</header>
<main>
<slot name="default"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</template>
<script>
export default {
name:"base-layout",
mounted:function(){
console.log(this);
console.log(this.$slots);
console.log(this.$slots.header);
console.log(this.$slots.header());
console.log(this.$slots.header()[0].el);
console.log(this.$slots.default()[0].el);
console.log(this.$slots.footer()[0].el);
}
}
</script>
node_modules/ant-design-vue/es/table/index.js
updateColumns(cols = []) {
const columns = [];
const { $slots, $scopedSlots } = this;
cols.forEach(col => {
const { slots = {}, scopedSlots = {}, ...restProps } = col;
const column = {
...restProps,
};
Object.keys(slots).forEach(key => {
const name = slots[key];
if (column[key] === undefined && $slots[name]) {
column[key] = $slots[name].length === 1 ? $slots[name][0] : $slots[name];
}
});
Object.keys(scopedSlots).forEach(key => {
const name = scopedSlots[key];
if (column[key] === undefined && $scopedSlots[name]) {
column[key] = $scopedSlots[name];
}
});
// if (slotScopeName && $scopedSlots[slotScopeName]) {
// column.customRender = column.customRender || $scopedSlots[slotScopeName]
// }
if (col.children) {
column.children = this.updateColumns(column.children);
}
columns.push(column);
});
return columns;
}
只有满足条件(column[key] === undefined && $slots[name])
,才能使用作用域插槽来自定义表头。本例中,dataIndex:'name'
想自定义表头,所以不能定义title
属性,而是在slots
属性中定义了title
属性。
node_modules/ant-design-vue/es/vc-table/src/TableCell.js
render() {
const {
record,
indentSize,
prefixCls,
indent,
index,
expandIcon,
column,
component: BodyCell,
} = this;
const { dataIndex, customRender, className = '' } = column;
const { transformCellText } = this.table;
// We should return undefined if no dataIndex is specified, but in order to
// be compatible with object-path's behavior, we return the record object instead.
let text;
if (typeof dataIndex === 'number') {
text = get(record, dataIndex);
} else if (!dataIndex || dataIndex.length === 0) {
text = record;
} else {
text = get(record, dataIndex);
}
let tdProps = {
props: {},
attrs: {},
on: {
click: this.handleClick,
},
};
let colSpan;
let rowSpan;
if (customRender) {
text = customRender(text, record, index, column);
if (isInvalidRenderCellText(text)) {
tdProps.attrs = text.attrs || {};
tdProps.props = text.props || {};
tdProps.class = text.class;
tdProps.style = text.style;
colSpan = tdProps.attrs.colSpan;
rowSpan = tdProps.attrs.rowSpan;
text = text.children;
}
}
if (column.customCell) {
tdProps = mergeProps(tdProps, column.customCell(record, index));
}
// Fix https://github.com/ant-design/ant-design/issues/1202
if (isInvalidRenderCellText(text)) {
text = null;
}
if (transformCellText) {
text = transformCellText({ text, column, record, index });
}
const indentText = expandIcon ? (
<span
style={{ paddingLeft: `${indentSize * indent}px` }}
class={`${prefixCls}-indent indent-level-${indent}`}
/>
) : null;
if (rowSpan === 0 || colSpan === 0) {
return null;
}
if (column.align) {
tdProps.style = { textAlign: column.align, ...tdProps.style };
}
const cellClassName = classNames(className, column.class, {
[`${prefixCls}-cell-ellipsis`]: !!column.ellipsis,
// 如果有宽度,增加断行处理
// https://github.com/ant-design/ant-design/issues/13825#issuecomment-449889241
[`${prefixCls}-cell-break-word`]: !!column.width,
});
if (column.ellipsis) {
if (typeof text === 'string') {
tdProps.attrs.title = text;
} else if (text) {
// const { props: textProps } = text;
// if (textProps && textProps.children && typeof textProps.children === 'string') {
// tdProps.attrs.title = textProps.children;
// }
}
}
return (
<BodyCell class={cellClassName} {...tdProps}>
{indentText}
{expandIcon}
{text}
</BodyCell>
);
}
其中,customRender
是渲染函数,用来对表中的值进行自定义渲染。该函数接受4个参数,分别是 text
、 record
、index
和 column
。
antd官网也有customRender
的相关说明,如下,