vue3拖拽布局+动态组件+自适应布局
/在package.json中dependencies下添加下面插件库,并执行命令npm install。Vue Grid Layout -️ 适用Vue.js的栅格布局系统。可拖动和可调整大小栅格布局的Vue组件。
·
1.拖拽布局插件
//在package.json中dependencies下添加下面插件库,并执行命令npm install
"vue-grid-layout": "^3.0.0-beta1",
2.拖拽页面代码
<template>
<div>
<!--
colNum: 定义栅格系统的列数,其值需为自然数.
rowHeight:每行的高度,单位像素。
isDraggable:标识栅格中的元素是否可拖拽.
isResizable:标识栅格中的元素是否可调整大小。
isMirrored:标识栅格中的元素是否可镜像反转。
autoSize:标识容器是否自动调整大小
verticalCompact:标识布局是否垂直压缩。
preventCollision:防止碰撞属性,值设置为ture时,栅格只能拖动至空白处。
useCssTransforms:标识是否使用CSS属性 transition-property: transform;
responsive:标识布局是否为响应式
-->
<grid-layout :layout="layout"
:col-num="12"
:row-height="30"
:is-draggable="true"
:is-resizable="true"
:vertical-compact="true"
:margin="[10, 10]"
:use-css-transforms="true"
@layout-updated="layoutUpdatedEvent">
<grid-item v-for="(item,index) in layout"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
@move="moveEvent"
@resized="resizedEvent"
style="background:pink;">
<keep-alive>
<component :is="item.name"
:ref="`dragRef${index}`"
:key="item.name+index"
:id="item.name+index"
:width="item.Wpx"
:height="item.Hpx"></component>
</keep-alive>
</grid-item>
</grid-layout>
</div>
</template>
<script lang="ts">
import { BarChart, FunnelChart, PieChart, RadarChart } from './components';
export default {
components: {
BarChart,
FunnelChart,
PieChart,
RadarChart
}
};
</script>
<script setup lang="ts">
const layout = ref([
{ x: 0, y: 0, w: 2, h: 2, i: '0' },
{ x: 2, y: 0, w: 2, h: 4, i: '1' },
{ x: 4, y: 0, w: 2, h: 5, i: '2' },
{ x: 6, y: 0, w: 2, h: 3, i: '3' },
{ x: 8, y: 0, w: 2, h: 3, i: '4' },
{ x: 10, y: 0, w: 2, h: 3, i: '5' }
]);
const testLayout = [
{
x: 0,
y: 0,
w: 2,
h: 8,
i: '0',
name: 'BarChart'
},
// {
// x: 2,
// y: 0,
// w: 2,
// h: 8,
// i: '1',
// name: 'FunnelChart'
// },
// {
// x: 4,
// y: 0,
// w: 2,
// h: 8,
// i: '2',
// name: 'PieChart'
// },
// {
// x: 6,
// y: 0,
// w: 2,
// h: 8,
// i: '3',
// name: 'RadarChart'
// },
{
x: 8,
y: 0,
w: 2,
h: 8,
i: '4',
name: 'BarChart'
}
];
layout.value = testLayout;
//更新事件(布局更新或栅格元素的位置重新计算)
const layoutUpdatedEvent = (newLayout: any) => {
console.log('布局更新了');
console.log('Updated layout: ', newLayout);
layout.value = newLayout;
console.log(layout.value);
};
//移动时的事件
const moveEvent = (i: any, newX: any, newY: any) => {
console.log('盒子移动了');
console.log('MOVE i=' + i + ', X=' + newX + ', Y=' + newY);
};
//调整大小后的事件
/**
*
* @param i the item id/index
* @param newH new height in grid rows
* @param newW new width in grid columns
* @param newHPx new height in pixels
* @param newWPx new width in pixels
*
*/
const resizedEvent = (
i: any,
newH: any,
newW: any,
newHPx: any,
newWPx: any
) => {
console.log('改变了尺寸');
console.log(
'RESIZED i=' +
i +
', H=' +
newH +
', W=' +
newW +
', H(px)=' +
newHPx +
', W(px)=' +
newWPx
);
let newLayouts = layout.value.map(item => {
console.log(item);
console.log(item.i == i);
if (item.i == i) {
item.Wpx = newWPx + 'px';
item.Hpx = newHPx + 'px';
}
return item;
});
layout.value = newLayouts;
};
</script>
<style scoped>
</style>
3.图表子组件代码
<template>
<div class="box">
<div :id="id"
:class="className"
:style="{ height, width }" />
</div>
</template>
<script setup lang="ts">
import * as echarts from 'echarts';
const props = defineProps({
id: {
type: String,
default: 'barChart'
},
className: {
type: String,
default: ''
},
width: {
type: String,
default: '100%',
required: true
},
height: {
type: String,
default: '100%',
required: true
}
});
const options = {
grid: {
left: '2%',
right: '2%',
// top: '5%',
bottom: '10%',
containLabel: true
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999'
}
}
},
legend: {
x: 'center',
y: 'bottom',
data: ['收入', '毛利润', '收入增长率', '利润增长率'],
textStyle: {
color: '#999'
}
},
xAxis: [
{
type: 'category',
data: ['浙江', '北京', '上海', '广东', '深圳'],
axisPointer: {
type: 'shadow'
}
}
],
yAxis: [
{
type: 'value',
min: 0,
max: 10000,
interval: 2000,
axisLabel: {
formatter: '{value} '
}
},
{
type: 'value',
min: 0,
max: 100,
interval: 20,
axisLabel: {
formatter: '{value}%'
}
}
],
series: [
{
name: '收入',
type: 'bar',
data: [7000, 7100, 7200, 7300, 7400],
barWidth: 20,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' }
])
}
},
{
name: '毛利润',
type: 'bar',
data: [8000, 8200, 8400, 8600, 8800],
barWidth: 20,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#25d73c' },
{ offset: 0.5, color: '#1bc23d' },
{ offset: 1, color: '#179e61' }
])
}
},
{
name: '收入增长率',
type: 'line',
yAxisIndex: 1,
data: [60, 65, 70, 75, 80],
itemStyle: {
color: '#67C23A'
}
},
{
name: '利润增长率',
type: 'line',
yAxisIndex: 1,
data: [70, 75, 80, 85, 90],
itemStyle: {
color: '#409EFF'
}
}
]
};
const initEcharts = () => {
console.log('123');
echarts.init(document.getElementById(props.id) as HTMLDivElement).dispose(); //先销毁
// 图表初始化
var chart = echarts.init(document.getElementById(props.id) as HTMLDivElement);
chart.setOption(options);
// 大小自适应
setTimeout(() => {
//由于网格布局拖拽放大缩小图表不能自适应,这里设置一个定时器使得echart加载为一个异步过程
console.log('111');
chart.resize();
}, 0);
};
watch(
() => props,
(newVal, oldVal) => {
console.log('监听传值', newVal);
initEcharts();
},
{
deep: true
}
);
onMounted(() => {
console.log('图表初始化');
initEcharts();
});
</script>
<style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
background: #fff;
}
</style>
更多推荐
已为社区贡献3条内容
所有评论(0)