ECharts基础学习 (第二天)

下定决心,好好过一天 ~

ECharts 异步加载数据

ECharts 通常数据设置在 setOption 中,如果我们需要异步加载数据,可以配合 jQuery等工具,在异步获取数据后通过 setOption 填入数据和配置项就行。

如果异步加载需要一段时间,我们可以添加 loading 效果,ECharts 默认有提供了一个简单的加载动画。只需要调用 showLoading 方法显示。数据加载完成后再调用 hideLoading 方法隐藏加载动画:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>第一个 ECharts 实例</title>
    <script src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));
		myChart.showLoading();  // 开启 loading 效果
	
        $.get('https://www.runoob.com/static/js/echarts_test_data.json', function (data) {
            alert("可以看到 loading 字样。"); // 测试代码,用于查看 loading 效果
			myChart.hideLoading();  // 隐藏 loading 效果
			myChart.setOption({
                series : [
                    {
                        name: '访问来源',
                        type: 'pie',    // 设置图表类型为饼图
                        radius: '55%',  // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
                        data:data.data_pie
                    }
                ]
            })
        }, 'json');
    </script>
</body>

数据的动态更新

ECharts 由数据驱动,数据的改变驱动图表展现的改变,因此动态数据的实现也变得异常简单。

所有数据的更新都通过 setOption 实现,你只需要定时获取数据,setOption 填入数据,而不用考虑数据到底产生了那些变化,ECharts 会找到两组数据之间的差异然后通过合适的动画去表现数据的变化。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>第一个 ECharts 实例</title>
    <script src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        var base = +new Date(2014, 9, 3);
		var oneDay = 24 * 3600 * 1000;
		var date = [];

		var data = [Math.random() * 150];
		var now = new Date(base);

		function addData(shift) {
		    now = [now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/');
		    date.push(now);
		    data.push((Math.random() - 0.4) * 10 + data[data.length - 1]);

		    if (shift) {
		        date.shift();
		        data.shift();
		    }

		    now = new Date(+new Date(now) + oneDay);
		}

		for (var i = 1; i < 100; i++) {
		    addData();
		}

		option = {
		    xAxis: {
		        type: 'category',
		        boundaryGap: false,
		        data: date
		    },
		    yAxis: {
		        boundaryGap: [0, '50%'],
		        type: 'value'
		    },
		    series: [
		        {
		            name:'成交',
		            type:'line',
		            smooth:true,
		            symbol: 'none',
		            stack: 'a',
		            areaStyle: {
		                normal: {}
		            },
		            data: data
		        }
		    ]
		};

		setInterval(function () {
		    addData(true);
		    myChart.setOption({
		        xAxis: {
		            data: date
		        },
		        series: [{
		            name:'成交',
		            data: data
		        }]
		    });
		}, 500);
		
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));
        myChart.setOption(option)
    </script>
</body>

ECharts 数据集(dataset)

ECharts 使用 dataset 管理数据。

dataset 组件用于单独的数据集声明,从而数据可以单独管理,被多个组件复用,并且可以基于数据指定数据到视觉的映射。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>第一个 ECharts 实例</title>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));
 
        // 指定图表的配置项和数据
        var option = {
            legend: {},
            tooltip: {},
            dataset: {
                // 提供一份数据。
                source: [
                    ['product', '2015', '2016', '2017'],
                    ['Matcha Latte', 43.3, 85.8, 93.7],
                    ['Milk Tea', 83.1, 73.4, 55.1],
                    ['Cheese Cocoa', 86.4, 65.2, 82.5],
                    ['Walnut Brownie', 72.4, 53.9, 39.1]
                ]
				 //dimensions: ['product', '2015', '2016', '2017'],
                    //source: [
                        //{product: 'Matcha Latte', '2015': 43.3, '2016': 85.8, '2017': 93.7},
                        //{product: 'Milk Tea', '2015': 83.1, '2016': 73.4, '2017': 55.1},
                        //{product: 'Cheese Cocoa', '2015': 86.4, '2016': 65.2, '2017': 82.5},
                        //{product: 'Walnut Brownie', '2015': 72.4, '2016': 53.9, '2017': 39.1}
                    ]
            },
            // 声明一个 X 轴,类目轴(category)。默认情况下,类目轴对应到 dataset 第一列。
            xAxis: {type: 'category'},
            // 声明一个 Y 轴,数值轴。
            yAxis: {},
            // 声明多个 bar 系列,默认情况下,每个系列会自动对应到 dataset 的每一列。
            series: [
                {type: 'bar'},
                {type: 'bar'},
                {type: 'bar'}
            ]
        };
 
        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>
</body>
</html>

数据到图形的映射

我们可以在配置项中将数据映射到图形中。
我们可以使用 series.seriesLayoutBy 属性来配置 dataset 是列(column)还是行(row)映射为图形系列(series),默认是按照列(column)来映射。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>第一个 ECharts 实例</title>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));
 
        // 指定图表的配置项和数据
        var option = {
                legend: {},
                tooltip: {},
                dataset: {
                    source: [
                        ['product', '2012', '2013', '2014', '2015'],
                        ['Matcha Latte', 41.1, 30.4, 65.1, 53.3],
                        ['Milk Tea', 86.5, 92.1, 85.7, 83.1],
                        ['Cheese Cocoa', 24.1, 67.2, 79.5, 86.4]
                    ]
                },
                xAxis: [
                    {type: 'category', gridIndex: 0},
                    {type: 'category', gridIndex: 1}
                ],
                yAxis: [
                    {gridIndex: 0},
                    {gridIndex: 1}
                ],
                grid: [
                    {bottom: '55%'},
                    {top: '55%'}
                ],
                series: [
                    // 这几个系列会在第一个直角坐标系中,每个系列对应到 dataset 的每一行。
                    {type: 'bar', seriesLayoutBy: 'row'},
                    {type: 'bar', seriesLayoutBy: 'row'},
                    {type: 'bar', seriesLayoutBy: 'row'},
                    // 这几个系列会在第二个直角坐标系中,每个系列对应到 dataset 的每一列。
                    {type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
                    {type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
                    {type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
                    {type: 'bar', xAxisIndex: 1, yAxisIndex: 1}
                ]
            }

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>
</body>
</html>

常用图表所描述的数据大部分是"二维表"结构,我们可以使用 series.encode 属性将对应的数据映射到坐标轴(如 X、Y 轴):

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>第一个 ECharts 实例</title>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));
 
        // 指定图表的配置项和数据
        var option = {
                dataset: {
                    source: [
                        ['score', 'amount', 'product'],
                        [89.3, 58212, 'Matcha Latte'],
                        [57.1, 78254, 'Milk Tea'],
                        [74.4, 41032, 'Cheese Cocoa'],
                        [50.1, 12755, 'Cheese Brownie'],
                        [89.7, 20145, 'Matcha Cocoa'],
                        [68.1, 79146, 'Tea'],
                        [19.6, 91852, 'Orange Juice'],
                        [10.6, 101852, 'Lemon Juice'],
                        [32.7, 20112, 'Walnut Brownie']
                    ]
                },
			    grid: {containLabel: true},
                xAxis: {},
                yAxis: {type: 'category'},
                series: [
                    {
                        type: 'bar',
                        encode: {
                            // 将 "amount" 列映射到 X 轴。
                            x: 'amount',
                            // 将 "product" 列映射到 Y 轴。
                            y: 'product'
                        }
                    }
                ]
            };

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>
</body>
</html>

encode 声明的基本结构如下,其中冒号左边是坐标系、标签等特定名称,如 ‘x’, ‘y’, ‘tooltip’ 等,冒号右边是数据中的维度名(string 格式)或者维度的序号(number 格式,从 0 开始计数),可以指定一个或多个维度(使用数组)。通常情况下,下面各种信息不需要所有的都写,按需写即可。

下面是 encode 支持的属性:

// 在任何坐标系和系列中,都支持:
encode: {
    // 使用 “名为 product 的维度” 和 “名为 score 的维度” 的值在 tooltip 中显示
    tooltip: ['product', 'score']
    // 使用 “维度 1” 和 “维度 3” 的维度名连起来作为系列名。(有时候名字比较长,这可以避免在 series.name 重复输入这些名字)
    seriesName: [1, 3],
    // 表示使用 “维度2” 中的值作为 id。这在使用 setOption 动态更新数据时有用处,可以使新老数据用 id 对应起来,从而能够产生合适的数据更新动画。
    itemId: 2,
    // 指定数据项的名称使用 “维度3” 在饼图等图表中有用,可以使这个名字显示在图例(legend)中。
    itemName: 3
}

// 直角坐标系(grid/cartesian)特有的属性:
encode: {
    // 把 “维度1”、“维度5”、“名为 score 的维度” 映射到 X 轴:
    x: [1, 5, 'score'],
    // 把“维度0”映射到 Y 轴。
    y: 0
}

// 单轴(singleAxis)特有的属性:
encode: {
    single: 3
}

// 极坐标系(polar)特有的属性:
encode: {
    radius: 3,
    angle: 2
}

// 地理坐标系(geo)特有的属性:
encode: {
    lng: 3,
    lat: 2
}

// 对于一些没有坐标系的图表,例如饼图、漏斗图等,可以是:
encode: {
    value: 3
}

视觉通道(颜色、尺寸等)的映射

我们可以使用 visualMap 组件进行视觉通道的映射。
视觉元素可以是:

1.ymbol: 图元的图形类别。
2.symbolSize: 图元的大小。
3.color: 图元的颜色。
4.colorAlpha: 图元的颜色的透明度。
5.opacity: 图元以及其附属物(如文字标签)的透明度。
6.colorLightness: 颜色的明暗度。
7.colorSaturation: 颜色的饱和度。
8.colorHue: 颜色的色调。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts 实例</title>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));
 
        var option = {
                dataset: {
                    source: [
                        ['score', 'amount', 'product'],
                        [89.3, 58212, 'Matcha Latte'],
                        [57.1, 78254, 'Milk Tea'],
                        [74.4, 41032, 'Cheese Cocoa'],
                        [50.1, 12755, 'Cheese Brownie'],
                        [89.7, 20145, 'Matcha Cocoa'],
                        [68.1, 79146, 'Tea'],
                        [19.6, 91852, 'Orange Juice'],
                        [10.6, 101852, 'Lemon Juice'],
                        [32.7, 20112, 'Walnut Brownie']
                    ]
                },
                grid: {containLabel: true},
                xAxis: {name: 'amount'},
                yAxis: {type: 'category'},
                visualMap: {
                    orient: 'horizontal',
                    left: 'center',
                    min: 10,
                    max: 100,
                    text: ['High Score', 'Low Score'],
                    // Map the score column to color
                    dimension: 0,
                    inRange: {
                        color: ['#D7DA8B', '#E15457']
                    }
                },
                series: [
                    {
                        type: 'bar',
                        encode: {
                            // Map the "amount" column to X axis.
                            x: 'amount',
                            // Map the "product" column to Y axis
                            y: 'product'
                        }
                    }
                ]
            };
	    myChart.setOption(option);
    </script>
</body>
</html>

在这里插入图片描述

ECharts 交互组件

ECharts 提供了很多交互组件:例组件 legend、标题组件 title、视觉映射组件 visualMap、数据区域缩放组件 dataZoom、时间线组件 timeline。

dataZoom

dataZoom 组件可以实现通过鼠标滚轮滚动,放大缩小图表的功能。
默认情况下 dataZoom 控制 x 轴,即对 x 轴进行数据窗口缩放和数据窗口平移操作。

dataZoom: [
                    {   // 这个dataZoom组件,默认控制x轴。
                        type: 'slider', // 这个 dataZoom 组件是 slider 型 dataZoom 组件
                        start: 10,      // 左边在 10% 的位置。
                        end: 60         // 右边在 60% 的位置。
                    },
                    {   // 这个dataZoom组件,也控制x轴。
                        type: 'inside', // 这个 dataZoom 组件是 inside 型 dataZoom 组件
                        start: 10,      // 左边在 10% 的位置。
                        end: 60         // 右边在 60% 的位置。
                    }
             
                ],
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts 实例</title>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));
 
        // 指定图表的配置项和数据
        var data1 = [];
        var data2 = [];
        var data3 = [];

        var random = function (max) {
            return (Math.random() * max).toFixed(3);
        };

        for (var i = 0; i < 500; i++) {
            data1.push([random(15), random(10), random(1)]);
            data2.push([random(10), random(10), random(1)]);
            data3.push([random(15), random(10), random(1)]);
        }

        option = {
            animation: false,
            legend: {
                data: ['scatter', 'scatter2', 'scatter3']
            },
            tooltip: {
            },
            xAxis: {
                type: 'value',
                min: 'dataMin',
                max: 'dataMax',
                splitLine: {
                    show: true
                }
            },
            yAxis: {
                type: 'value',
                min: 'dataMin',
                max: 'dataMax',
                splitLine: {
                    show: true
                }
            },
            dataZoom: [
                {
                    type: 'slider',
                    show: true,
                    xAxisIndex: [0],
                    start: 1,
                    end: 35
                },
                {
                    type: 'slider',
                    show: true,
                    yAxisIndex: [0],
                    left: '93%',
                    start: 29,
                    end: 36
                },
                {
                    type: 'inside',
                    xAxisIndex: [0],
                    start: 1,
                    end: 35
                },
                {
                    type: 'inside',
                    yAxisIndex: [0],
                    start: 29,
                    end: 36
                }
            ],
            series: [
                {
                    name: 'scatter',
                    type: 'scatter',
                    itemStyle: {
                        normal: {
                            opacity: 0.8
                        }
                    },
                    symbolSize: function (val) {
                        return val[2] * 40;
                    },
                    data: data1
                },
                {
                    name: 'scatter2',
                    type: 'scatter',
                    itemStyle: {
                        normal: {
                            opacity: 0.8
                        }
                    },
                    symbolSize: function (val) {
                        return val[2] * 40;
                    },
                    data: data2
                },
                {
                    name: 'scatter3',
                    type: 'scatter',
                    itemStyle: {
                        normal: {
                            opacity: 0.8,
                        }
                    },
                    symbolSize: function (val) {
                        return val[2] * 40;
                    },
                    data: data3
                }
            ]
        }
 
        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>
</body>
</html>

在这里插入图片描述

ECharts 响应式

ECharts 图表显示在用户指定高宽的 DOM 节点(容器)中。

有时候我们希望在 PC 和 移动设备上都能够很好的展示图表的内容,实现响应式的设计,为了解决这个问题,ECharts 完善了组件的定位设置,并且实现了类似 CSS Media Query 的自适应能力。

ECharts 组件的定位和布局

大部分『组件』和『系列』会遵循两种定位方式。

left/right/top/bottom/width/height 定位方式

这六个量中,每个量都可以是『绝对值』或者『百分比』或者『位置描述』。

绝对值
单位是浏览器像素(px),用 number 形式书写(不写单位)。例如 {left: 23, height: 400}。

百分比
表示占 DOM 容器高宽的百分之多少,用 string 形式书写。例如 {right: ‘30%’, bottom: ‘40%’}。

位置描述
可以设置 left: ‘center’,表示水平居中。
可以设置 top: ‘middle’,表示垂直居中。

这六个量的概念,和 CSS 中六个量的概念类似:
left:距离 DOM 容器左边界的距离。
right:距离 DOM 容器右边界的距离。
top:距离 DOM 容器上边界的距离。
bottom:距离 DOM 容器下边界的距离。
width:宽度。
height:高度。

在横向,left、right、width 三个量中,只需两个量有值即可,因为任两个量可以决定组件的位置和大小,例如 left 和 right 或者 right 和 width 都可以决定组件的位置和大小。 纵向,top、bottom、height 三个量,和横向类同不赘述。

center / radius 定位方式

1.center
是一个数组,表示 [x, y],其中,x、y可以是『绝对值』或者『百分比』,含义和前述相同。

2.radius
是一个数组,表示 [内半径, 外半径],其中,内外半径可以是『绝对值』或者『百分比』,含义和前述相同。
在自适应容器大小时,百分比设置是很有用的。

横向(horizontal)和纵向(vertical)

ECharts的『外观狭长』型的组件(如 legend、visualMap、dataZoom、timeline等),大多提供了『横向布局』『纵向布局』的选择。例如,在细长的移动端屏幕上,可能适合使用『纵向布局』;在PC宽屏上,可能适合使用『横向布局』。

横纵向布局的设置,一般在『组件』或者『系列』的 orient 或者 layout 配置项上,设置为 ‘horizontal’ 或者 ‘vertical’。

要在 option 中设置 Media Query 须遵循如下格式:

option = {
    baseOption: { // 这里是基本的『原子option』。
        title: {...},
        legend: {...},
        series: [{...}, {...}, ...],
        ...
    },
    media: [ // 这里定义了 media query 的逐条规则。
        {
            query: {...},   // 这里写规则。
            option: {       // 这里写此规则满足下的option。
                legend: {...},
                ...
            }
        },
        {
            query: {...},   // 第二个规则。
            option: {       // 第二个规则对应的option。
                legend: {...},
                ...
            }
        },
        {                   // 这条里没有写规则,表示『默认』,
            option: {       // 即所有规则都不满足时,采纳这个option。
                legend: {...},
                ...
            }
        }
    ]
};

上面的例子中,baseOption、以及 media 每个 option 都是『原子 option』,即普通的含有各组件、系列定义的 option。而由『原子option』组合成的整个 option,我们称为『复合 option』。baseOption 是必然被使用的,此外,满足了某个 query 条件时,对应的 option 会被使用 chart.mergeOption() 来 merge 进去。

query

{
    minWidth: 200,
    maxHeight: 300,
    minAspectRatio: 1.3
}

现在支持三个属性:width、height、aspectRatio(长宽比)。每个属性都可以加上 min 或 max 前缀。比如,minWidth: 200 表示『大于等于200px宽度』。两个属性一起写表示『并且』,比如:{minWidth: 200, maxHeight: 300} 表示『大于等于200px宽度,并且小于等于300px高度』。

option
media中的 option 既然是『原子 option』,理论上可以写任何 option 的配置项。但是一般我们只写跟布局定位相关的,例如截取上面例子中的一部分 query option:

media: [
    ...,
    {
        query: {
            maxAspectRatio: 1           // 当长宽比小于1时。
        },
        option: {
            legend: {                   // legend 放在底部中间。
                right: 'center',
                bottom: 0,
                orient: 'horizontal'    // legend 横向布局。
            },
            series: [                   // 两个饼图左右布局。
                {
                    radius: [20, '50%'],
                    center: ['50%', '30%']
                },
                {
                    radius: [30, '50%'],
                    center: ['50%', '70%']
                }
            ]
        }
    },
    {
        query: {
            maxWidth: 500               // 当容器宽度小于 500 时。
        },
        option: {
            legend: {
                right: 10,              // legend 放置在右侧中间。
                top: '15%',
                orient: 'vertical'      // 纵向布局。
            },
            series: [                   // 两个饼图上下布局。
                {
                    radius: [20, '50%'],
                    center: ['50%', '30%']
                },
                {
                    radius: [30, '50%'],
                    center: ['50%', '75%']
                }
            ]
        }
    },
    ...
]

多个 query 被满足时的优先级

注意,可以有多个 query 同时被满足,会都被 mergeOption,定义在后的后被 merge(即优先级更高)。

默认 query

如果 media 中有某项不写 query,则表示『默认值』,即所有规则都不满足时,采纳这个option。

容器大小实时变化时的注意事项

在不少情况下,并不需要容器DOM节点任意随着拖拽变化大小,而是只是根据不同终端设置几个典型尺寸。

但是如果容器DOM节点需要能任意随着拖拽变化大小,那么目前使用时需要注意这件事:某个配置项,如果在某一个 query option 中出现,那么在其他 query option 中也必须出现,否则不能够回归到原来的状态。(left/right/top/bottom/width/height 不受这个限制。)

『复合 option』 中的 media 不支持 merge

也就是说,当第二(或三、四、五 …)次 chart.setOption(rawOption) 时,如果 rawOption 是 复合option(即包含 media 列表),那么新的 rawOption.media 列表不会和老的 media 列表进行 merge,而是简单替代。当然,rawOption.baseOption 仍然会正常和老的 option 进行merge。 其实,很少有场景需要使用『复合 option』来多次 setOption,而我们推荐的做法是,使用 mediaQuery 时,第一次setOption使用『复合 option』,后面 setOption 时仅使用 『原子 option』,也就是仅仅用 setOption 来改变 baseOption。

参考资料

下定决心,好好过一天 ~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值