1、我想要实现的效果图,中间的 图形加文字的 方块 列效果就是自定义组件实现的。

2、组件页面的代码:
TypeScript
<template>
<div class="box">
<div v-for="(item) in data" :key="item.id" class="card">
<img :src="item?.image || logo" class="card-img" />
<div class="card-name"><b> {{ item.name }} </b> </div>
<div class="card-desc">
<span>规格: {{ item.spec }} </span>
<span>单位: {{ item.unitFkDisplayName }} 成本: {{ item.costPrice }} 元</span>
<span></span>
</div>
<div class="card-footer">
<el-button type="primary" size="small" @click="handleDetail(item)">详情</el-button>
<el-button type="primary" size="small" @click="handleSelect(item)">选中</el-button>
</div>
</div>
</div>
</template>
<script setup>
import logo from '/@/assets/logo1.png'
import {ref,watch} from 'vue'
const emits = defineEmits(['select','clickDetail'])
const props = defineProps({
items: {
type: Object,
default: ()=> {
return [];
}
}
})
const data= ref([]);
watch(
() => props.items, (newValue) => {
data.value = newValue;
},
{ immediate: true, deep: true }
)
// 选中按钮事件
function handleSelect(row){
// debugger;
emits('select',row); //声明父组件上自定义事件,传递参数给父组件
// console.log(row);
}
// 详情按钮
function handleDetail(row) {
console.log(row);
emits('clickDetail',row); //声明父组件上自定义事件,传递参数给父组件
}
</script>
<style lang="scss" scoped>
.box {
box-sizing: border-box;
background-color: #FFFFFF;
display: flex;
flex-direction: column;
justify-content: flex-start; //这个使用center属性会导致列表内的内容超出范围时,会在上面被截断。
align-items: center;
height: 100%; /* 或者你希望的任何高度 */
overflow-y:visible; /* 只显示垂直滚动条 */
overflow-x: hidden; /* 隐藏水平滚动条,如果需要的话 */
}
.card {
display: flex;
flex-direction: column;
justify-content: start;
align-items: center;
width: 250px;
border: 1px solid #868686;
padding: 4px;
margin: 4px 0;
&-img {
width: 100px;
height: 100px;
}
&-name {
line-height: 30px;
}
&-desc {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
width: 100%;
line-height: 20px;
}
&-footer {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
width: 100%;
}
}
</style>
3、展现组件的页面中相关代码:
TypeScript
<template>
<!--elemet 呈现组件的页面代码中,显示组件的代码,上其他内容都忽略了,-->
<Pane size="20" style="height: 650px; ">
<ImageTextList ref="ImageTextListRef" :items="centerItems" @select="handleSelect" @clickDetail="handleDetail" />
</Pane>
</template>
<script lang="ts" setup="" name="cbbjCostPriceDetail">
//图片文字方块 组件
import ImageTextList from './imageBox.vue';
const ImageTextListRef = ref<InstanceType<typeof ImageTextList>>();
// 中间物料信息列表接受数据的对象,这个对象就要根据自己需要填充一条数据给他。比如我的就是通过左侧树组件点击事件nodeClick 从后端API获取数据填充的
const centerItems = ref([]);
// 树组件点击
const nodeClick = async (node: any) => {
state.queryParams.typeId = node.id;
state.queryParams_detail.typeId = node.id;
const params = Object.assign(state.queryParams, { page: 1, pageSize: 9999, descStr: 'desc' });
const params_detail = Object.assign(state.queryParams_detail, { page: 1, pageSize: 9999, descStr: 'desc' });
// debugger;
const result = await await cbbjMaterialApi.page(params);
if(result?.data?.result?.items){
//下面一行这里就是填充自定义组件数据对象的
centerItems.value = result?.data?.result?.items;
centerItems.value.forEach(item => {
item.image = window.__env__.VITE_PUBLIC_PATH+"/"+item.image;
});
}
handleQuery();
await handleQueryApi(params.page, params.order);
};
/**
* 中间选择事件
* @param row
*/
async function handleSelect(row) {
console.log('select', row);
// debugger;
//你可以根据需要在这里调用组件中的按钮,做你想要实现的事
}
/**
* 中间详情按钮事件
* @param row
*/
async function handleDetail(row) {
console.log('select', row);
// debugger;
//你可以根据需要在这里调用组件中的按钮,做你想要实现的事
}
</script>