1.点个数太多导致加载缓慢的解决。
2.可视化区域内加载的解决。
3.自定义信息窗口解决。
4.区域/板块/商圈等的绘制功能解决。
基本包含了用到百度地图API会使用到的大部分常规性场景。(聚合点功能没写,公司暂不需要)
上两份代码。
var map = null;
var estateResult;
var landResult;
var myIcon1 = new BMap.Icon("../../Img/marker1.png", new BMap.Size(48, 48));
var myIcon2 = new BMap.Icon("../../Img/marker2.png", new BMap.Size(48, 48));
var myIcon3 = new BMap.Icon("../../Img/marker3.png", new BMap.Size(48, 48));
var local;
var searchText = null;
var points = [];
var center;
var leftBottom;
var rightTop;
var curLng;
var curLat;
var curType; var leftlng;
var leftlat;
var rightlng;
var rightlat;
function InitialSearch() { local = new BMap.LocalSearch(map, {
renderOptions: { map: map, panel: "mapSearchContainer" },
onSearchComplete: function (results) {
if (local.getStatus() == BMAP_STATUS_SUCCESS) {
// 判断状态是否正确
points = [];
debugger
for (var i = 0; i < results.getCurrentNumPois() ; i++) {
points.push(results.getPoi(i).point);
}
}
}
});
} function InitialMap(lng, lat, type, flag) {
curLng = lng;
curLat = lat;
curType = type;
map = new BMap.Map("estatemapContainer", { minZoom: 13, maxZoom: 20 });
var top_left_control = new BMap.ScaleControl({ anchor: BMAP_ANCHOR_TOP_LEFT });
var top_left_navigation = new BMap.NavigationControl();
var top_right_navigation = new BMap.NavigationControl({ anchor: BMAP_ANCHOR_TOP_RIGHT, type: BMAP_NAVIGATION_CONTROL_SMALL });
map.addControl(top_left_control);
map.addControl(top_left_navigation);
map.addControl(top_right_navigation);
map.enableDragging();
map.enableScrollWheelZoom();
var point = new BMap.Point(lng, lat);
var marker;
if (type == "land") {
marker = new BMap.Marker(point, { icon: myIcon3 });
}
else {
marker = new BMap.Marker(point, { icon: myIcon2 }); } map.addOverlay(marker);
marker.setAnimation(BMAP_ANIMATION_BOUNCE);
map.centerAndZoom(new BMap.Point(lng, lat), 15);
if (type == "land") {
$("#EstateContent").hide();
$("#LandContent").show();
}
else {
$("#LandContent").hide();
$("#EstateContent").show();
if (flag == "have")
$("#pageLandInfo").show();
else
$("#pageLandInfo").hide(); }
}
function InitInfo(id) {
$.ajax({
url: "/Map/GetEstateData",
data: { id: id },
dataType: "json",
type: "POST",
async: false,
success: function (result) {
$("#estateName").text(result.EstateModel.ItemName);
$("#floorArea").text(result.EstateModel.FloorArea + "(亩)");
$("#developer").text(result.EstateModel.Developer);
$("#agentor").text(result.EstateModel.Agentor);
$("#firstDate").text(result.EstateModel.FirstOpenDate);
$("#itemStatus").text(result.EstateModel.ItemStatus); if (result.EstateList != null) {
var firstLi = '<li class="js_xf_map curr" onmouseover=TabMsg(this,"' + result.EstateModel.IsHardback + '","' + result.EstateModel.HouseSquare + '","' + result.EstateModel.TotalHouse + '") style="padding-top:3px;padding-bottom:0px;font-size: 14px;" zvalue="' + result.EstateModel.BuildingType + '">' + result.EstateModel.BuildingType + '</li>';
$(".live-nav").append(firstLi);
for (var i = 0; i < result.EstateList.length; i++) {
var li = "<li class='js_xf_map' onmouseover=TabMsg(this,'" + result.EstateList[i].IsHardback + "','" + result.EstateList[i].HouseSquare + "','" + result.EstateList[i].TotalHouse + "') style='padding-top:3px;padding-left:1px;padding-bottom:0px;font-size: 14px;' zvalue='" + result.EstateList[i].BuildingType + "'>" + result.EstateList[i].BuildingType + "</li>";
$(".live-nav").append(li);
}
$("#autoLi").show();
$("#buildLi").hide();
}
else {
$("#autoLi").hide();
$("#buildLi").show();
}
$("#buildType").text(result.EstateModel.BuildingType);
$("#isHardback").text(result.EstateModel.IsHardback);
$("#houseSquare").text(result.EstateModel.HouseSquare + "(m²)");
$("#totalHouse").text(result.EstateModel.TotalHouse + "(套)"); if (result.LandModel != null) {
var str;
if (result.LandModel.GetPeople.length > 14)
str = result.LandModel.GetPeople.substring(0, 12) + "..."
else
str = result.LandModel.GetPeople;
$(".getPeople").attr("title", result.LandModel.GetPeople);
$(".getPeople").text(str);
$(".price").text(result.LandModel.ContractAmount + "(万元)");
$(".square").text(result.LandModel.NetSquareAcre + "(亩)");
$(".floorPrice").text(result.LandModel.FloorPrice + "(元/m²)");
$(".ratio").text(result.LandModel.PremiumRatio + "%");
$(".developerSize").text(result.LandModel.DeveloperSize + "(万m²)");
$("#pageLandInfo").show();
}
else {
$("#pageLandInfo").hide();
}
}
}); }
function TabMsg(obj, isHardback, houseSquare, totalHouse) {
$(obj).addClass("curr").siblings().removeClass("curr");
$("#isHardback").text(isHardback);
$("#houseSquare").text(houseSquare + "(m²)");
$("#totalHouse").text(totalHouse + "(套)");
}
function GetMapData() { $.ajax({
url: "/Map/GetMapData",
dataType: "json",
type: "POST",
async: false,
success: function (result) {
debugger
estateResult = result.EstateList;
landResult = result.LandList;
},
});
} function CreateVisableZoom() { center = map.getBounds();
leftBottom = center.getSouthWest();
rightTop = center.getNorthEast(); leftlng = leftBottom.lng;
leftlat = leftBottom.lat;
rightlng = rightTop.lng;
rightlat = rightTop.lat;
debugger
var isHaveLand = false;
var isHaveEstate = false; for (var j = 0; j < landResult.length; j++) {
if (landResult[j].Longitude > leftlng && landResult[j].Longitude < rightlng
&& landResult[j].Latitude > leftlat && landResult[j].Latitude < rightlat) { addCustomPoint(landResult[j]);
} } for (var i = 0; i < estateResult.length; i++) {
if (estateResult[i].Longitude > leftlng && estateResult[i].Longitude < rightlng
&& estateResult[i].Latitude > leftlat && estateResult[i].Latitude < rightlat) { addPoint(estateResult[i]);
} } //debugger
//if (points.length > 0) { // for (var i = 0; i < points.length; i++) {
// var point = new BMap.Point(points[i].lng, points[i].lat);
// var marker = new BMap.Marker(point);
// map.addOverlay(marker);
// } //} //if (searchText != "" && searchText != null) {
// localSearch(searchText)
//}
} function addDragHandlerEstate() {
map.addEventListener("dragend", function () {
map.clearOverlays();
CreateVisableZoom(); });
} function addMoveHandlerEstate() {
map.addEventListener("moveend", function () { map.clearOverlays();
CreateVisableZoom(); });
} function addZoomHandlerEstate() {
map.addEventListener("zoomend", function () { map.clearOverlays();
CreateVisableZoom(); }); } function addPoint(data) { var point = new BMap.Point(data.Longitude, data.Latitude);
addMarker(point, data); } function addMarker(point, data) {
var marker = new BMap.Marker(point, { icon: myIcon2 });
if (data.ItemName != null && data.ItemName != "") {
var label = new BMap.Label(data.ItemName, { offset: new BMap.Size(20, 4) });
marker.setLabel(label);
}
addClickHandler(data, marker, 1)
map.addOverlay(marker);
if (data.Longitude == curLng && data.Latitude == curLat) {
marker.setAnimation(BMAP_ANIMATION_BOUNCE);
}
} function addCustomPoint(data) { var point = new BMap.Point(data.Longitude, data.Latitude);
addCustomMarker(point, data);
} function addCustomMarker(point, data) { var marker = new BMap.Marker(point, { icon: myIcon3 });
if (data.ItemView != null && data.ItemView != "") {
var label = new BMap.Label(data.ItemView, { offset: new BMap.Size(20, 4) });
marker.setLabel(label); } addClickHandler(data, marker, 0)
map.addOverlay(marker);
if (data.Longitude == curLng && data.Latitude == curLat) {
marker.setAnimation(BMAP_ANIMATION_BOUNCE);
} } function addClickHandler(data, marker, type) {
marker.addEventListener("click", function (e) {
map.panTo(e.point)
if (type == 0) {
var str;
if (data.GetPeople != null && data.GetPeople.length > 14)
str = data.GetPeople.substring(0, 12) + "..."
else
str = data.GetPeople;
$("#getPeople").attr("title", data.GetPeople);
$("#getPeople").text(str);
$("#price").text(data.ContractAmount + "(万元)");
$("#square").text(data.NetSquareAcre + "(亩)");
$("#floorPrice").text(data.FloorPrice + "(元/m²)");
$("#ratio").text(data.PremiumRatio + "%");
$("#developerSize").text(data.DeveloperSize + "(万m²)"); $("#LandContent").show();
$("#EstateContent").hide(); }
else {
$.ajax({
url: "/Map/GetEstateData",
data: { id: data.ID },
dataType: "json",
type: "POST",
async: false,
success: function (result) {
$("#estateName").text(result.EstateModel.ItemName);
$("#developer").text(result.EstateModel.Developer);
$("#agentor").text(result.EstateModel.Agentor);
$("#firstDate").text(result.EstateModel.FirstOpenDate);
$("#floorArea").text(result.EstateModel.FloorArea + "(亩)");
$("#itemStatus").text(result.EstateModel.ItemStatus); if (result.EstateList != null) {
$(".live-nav").find("li").remove();
var firstLi = '<li class="js_xf_map curr" onmouseover=TabMsg(this,"' + result.EstateModel.IsHardback + '","' + result.EstateModel.HouseSquare + '","' + result.EstateModel.TotalHouse + '") style="padding-top:3px;padding-bottom:0px;font-size: 14px;" zvalue="' + result.EstateModel.BuildingType + '">' + result.EstateModel.BuildingType + '</li>';
$(".live-nav").append(firstLi);
for (var i = 0; i < result.EstateList.length; i++) {
var li = "<li class='js_xf_map' onmouseover=TabMsg(this,'" + result.EstateList[i].IsHardback + "','" + result.EstateList[i].HouseSquare + "','" + result.EstateList[i].TotalHouse + "') style='padding-top:3px;padding-left:1px;padding-bottom:0px;font-size: 14px;' zvalue='" + result.EstateList[i].BuildingType + "'>" + result.EstateList[i].BuildingType + "</li>";
$(".live-nav").append(li);
}
$("#autoLi").show();
$("#buildLi").hide();
}
else {
$("#autoLi").hide();
$("#buildLi").show();
}
$("#buildType").text(result.EstateModel.BuildingType);
$("#isHardback").text(result.EstateModel.IsHardback);
$("#houseSquare").text(result.EstateModel.HouseSquare + "(m²)");
$("#totalHouse").text(result.EstateModel.TotalHouse + "(套)"); if (result.LandModel != null) {
var str;
if (result.LandModel.GetPeople.length > 14)
str = result.LandModel.GetPeople.substring(0, 12) + "..."
else
str = result.LandModel.GetPeople;
$(".getPeople").attr("title", result.LandModel.GetPeople);
$(".getPeople").text(str);
$(".price").text(result.LandModel.ContractAmount + "(万元)");
$(".square").text(result.LandModel.NetSquareAcre + "(亩)");
$(".floorPrice").text(result.LandModel.FloorPrice + "(元/m²)");
$(".ratio").text(result.LandModel.PremiumRatio + "%");
$(".developerSize").text(result.LandModel.DeveloperSize + "(万m²)");
$("#pageLandInfo").show();
}
else {
$("#pageLandInfo").hide();
}
},
}); $("#EstateContent").show();
$("#LandContent").hide();
}
});
} function localSearch(searchText) {
searchInBounds(searchText); //map.addEventListener("dragend", function () {
// local.searchInBounds(searchText, map.getBounds());
//});
} function searchInBounds(searchText) {
var pStart = new BMap.Point(leftlng, leftlat);
var pEnd = new BMap.Point(rightlng, rightlat);
var bs = new BMap.Bounds(pStart, pEnd);
local.searchInBounds(searchText, bs);
}
区域绘制功能:
var map = new BMap.Map('labelmapContainer', { minZoom: 12, maxZoom: 18 });
var poi = new BMap.Point(104.072385, 30.666158);
var objecrArr = [];
map.centerAndZoom(poi, 16);
map.enableScrollWheelZoom(); var IsEdit = false;
var drawType;
var overlays = []; var markercomplete = function (overlay) {
debugger
setCenter(overlay.point.lng, overlay.point.lat);
} var polygoncomplete = function (overlay) {
overlays = [];
overlays.push(overlay);
getPoint();
uploadPoints();
};
var styleOptions = {
strokeColor: "rgb(239, 58, 58)", //边线颜色。
fillColor: "rgba(220, 58, 58, 0.18)", //填充颜色。当参数为空时,圆形将没有填充效果。
strokeWeight: 2, //边线的宽度,以像素为单位。
strokeOpacity: 1, //边线透明度,取值范围0 - 1。
fillOpacity: 0, //填充的透明度,取值范围0 - 1。
strokeStyle: 'solid',//边线的样式,solid或dashed。
enableClicking: !1
}
var colorStyles = [
{
strokeColor: "#080808",
fillColor: "rgba(220, 58, 58, 0.58)",
strokeWeight: 2,
strokeOpacity: 1,
fillOpacity: 0,
strokeStyle: 'solid',
enableClicking: !1
},
{
strokeColor: "#080808",
fillColor: "rgba(52, 188, 239, 0.58)",
strokeWeight: 2,
strokeOpacity: 1,
fillOpacity: 0,
strokeStyle: 'solid',
},
{
strokeColor: "#080808",
fillColor: "rgba(156, 39, 176, 0.58)",
strokeWeight: 2,
strokeOpacity: 1,
fillOpacity: 0,
strokeStyle: 'solid',
},
{
strokeColor: "#080808", //边线颜色。
fillColor: "rgba(76, 175, 80, 0.58)", //填充颜色。当参数为空时,圆形将没有填充效果。
strokeWeight: 2, //边线的宽度,以像素为单位。
strokeOpacity: 1, //边线透明度,取值范围0 - 1。
fillOpacity: 0, //填充的透明度,取值范围0 - 1。
strokeStyle: 'solid',//边线的样式,solid或dashed。
enableClicking: !1
},
{
strokeColor: "#080808",
fillColor: "rgba(63, 81, 181, 0.58)",
strokeWeight: 2,
strokeOpacity: 1,
fillOpacity: 0,
strokeStyle: 'solid'
},
{
strokeColor: "#080808", //边线颜色。
fillColor: "rgba(249, 217, 50, 0.58)", //填充颜色。当参数为空时,圆形将没有填充效果。
strokeWeight: 2, //边线的宽度,以像素为单位。
strokeOpacity: 1, //边线透明度,取值范围0 - 1。
fillOpacity: 0, //填充的透明度,取值范围0 - 1。
strokeStyle: 'solid',//边线的样式,solid或dashed。
enableClicking: !1
}
]; var drawingManager = new BMapLib.DrawingManager(map, {
isOpen: false,
enableDrawingTool: true,
drawingToolOptions: {
anchor: BMAP_ANCHOR_TOP_RIGHT, //位置
offset: new BMap.Size(5, 5), //偏离值
},
circleOptions: styleOptions, //圆的样式
polylineOptions: styleOptions, //线的样式
polygonOptions: styleOptions, //多边形的样式
rectangleOptions: styleOptions //矩形的样式
}); drawingManager.addEventListener('polygoncomplete', polygoncomplete); drawingManager.addEventListener('markercomplete', markercomplete); function showArea() {
map.clearOverlays();
var poi = new BMap.Point(104.072385, 30.666158);
var objecrArr = [];
map.centerAndZoom(poi, 12);
map.enableScrollWheelZoom(); getPointsByZoom();
addZoomHandlerEstate(); } function showAllArea() {
$.ajax({
url: "/Map/GetAllArea",
type: "Post",
dataType: 'json',
success: function (result) {
if (result != null && result.length > 0) {
map.setZoom(16);
for (var i = 0; i < result.length; i++) {
debugger
var name = result[i].Name;
var pnts = [];
for (var j = 0; j < result[i].PointsList.length; j++) {
var point = new BMap.Point(result[i].PointsList[j].Longitude, result[i].PointsList[j].Latitude);
pnts.push(point);
}
var polygon = new BMap.Polygon(pnts, styleOptions); //创建多边形 var center = new BMap.Point(result[i].Longitude, result[i].Latitude);
map.panTo(center);
var txt = "抚琴", mouseoverTxt = txt + " " + parseInt(Math.random() * 1000, 10) + "套"; var myCompOverlay = new ComplexCustomOverlay(center, name); map.addOverlay(myCompOverlay); map.addOverlay(polygon); //增加多边形
}
}
else {
alert("获取失败,请联系管理员..."); } }
});
}; function setCenter(ln, la) {
$.ajax({
url: '/Map/SetAreaCenter',
type: 'post',
data: { name: $("#regionName").val(), level: $('#areaSelect option:selected').val(), lng: ln, lat: la },
dataType: "json",
success: function (result) {
if (result.Status == true) {
ShowFlashMsg('保存成功...', 'success');
map.clearOverlays();
drawingManager.close();
}
else {
ShowFlashMsg('服务器内部错误...', 'error');
drawingManager.close();
}
}
}); } function uploadPoints() {
$.ajax({
url: '/Map/UploadPoints',
type: 'post',
data: { name: $("#regionName").val(), points: JSON.stringify(objecrArr) },
dataType: "json",
success: function (result) {
if (result.Status == true) {
ShowFlashMsg('保存成功...', 'success');
map.clearOverlays();
drawingManager.close();
$("#regionName").val("");
}
else {
ShowFlashMsg('服务器内部错误...', 'error');
drawingManager.close();
}
}
}); } function draw(type) {
if ($("#regionName").val() == "") {
$.messager.alert('提醒', '请输入区域名称......');
}
else {
map.clearOverlays();
drawingManager.open();
if (type == BMAP_DRAWING_MARKER) { drawingManager.setDrawingMode(type);
}
else {
$.ajax({
url: "/Map/CheckCenterExist",
type: 'Post',
async: false,
data: { name: $("#regionName").val() },
dataType: 'json',
success: function (result) {
if (result.Status == true) {
drawingManager.setDrawingMode(type);
}
else {
$.messager.alert('提醒', result.ErrorMsg);
drawingManager.close();
}
}
}); }
} } function clearAll() {
for (var i = 0; i < overlays.length; i++) {
map.removeOverlay(overlays[i]);
}
overlays.length = 0
} function getPoint() {
objecrArr = [];
for (var i = 0; i < overlays.length; i++) {
var overlay = overlays[i].getPath();
for (var j = 0; j < overlay.length; j++) {
var grid = overlay[j];
objecrArr.push(grid);
}
}
}
var editPolygons = [];
var editPolygon = null; function Editing() {
editPolygons = [];
if ($("#regionName").val() == "") {
$.messager.alert('提醒', '请输入区域名称......');
}
else {
$.ajax({
url: "/Map/GetPolygonByName",
type: "Post",
data: { name: $("#regionName").val() },
dataType: 'json',
async: false,
success: function (result) {
if (result != null) {
map.clearOverlays();
map.setZoom(16);
var pnts = [];
for (var j = 0; j < result.PointsList.length; j++) {
var point = new BMap.Point(result.PointsList[j].Longitude, result.PointsList[j].Latitude);
pnts.push(point);
}
var center = new BMap.Point(result.Longitude, result.Latitude);
map.panTo(center);
editPolygon = new BMap.Polygon(pnts, styleOptions); //创建多边形
editPolygons.push(editPolygon)
map.addOverlay(editPolygon); //增加多边形 }
else {
$.messager.alert('提醒', '输入名称有误......');
} }
});
for (var i = 0; i < editPolygons.length; i++) {
editPolygons[i].enableEditing();
}
}
}
var editPoints = []; function SaveEditing() {
if ($("#regionName").val() == "") {
$.messager.alert('提醒', '请输入区域名称......');
}
else {
debugger
var arr = editPolygon.getPath();
$.ajax({
url: "/Map/SaveEdit",
type: "post",
data: { name: $("#regionName").val(), points: JSON.stringify(arr) },
dataType: "json",
success: function (result) {
if (result.Status == true) {
ShowFlashMsg('保存成功...', 'success');
map.clearOverlays();
}
else {
$.messager.alert('提醒', '保存失败,请联系管理员...');
}
}
});
}
} function addZoomHandlerEstate() {
map.addEventListener("zoomend", function () {
map.clearOverlays();
getPointsByZoom();
}); }
function getPointsByZoom() {
var zoom = map.getZoom();
$.ajax({
url: "/map/GetPointsByZoom",
type: "post",
data: { type: zoom },
dataType: "json",
success: function (result) {
if (zoom == 12 || zoom == 13) { for (var i = 0; i < result.length; i++) { var name = result[i].Name; var borderData = "";
var points = [];
for (var j = 0; j < result[i].PointsList.length; j++) {
var p = new BMap.Point(result[i].PointsList[j].Longitude, result[i].PointsList[j].Latitude);
points.push(p)
}
var pol = new BMap.Polygon(points, colorStyles[i]); //创建多边形 map.addOverlay(pol);
var center = new BMap.Point(result[i].Longitude, result[i].Latitude);
var myCompOverlay = new ComplexCustomOverlay(center, result[i].Name, borderData);
map.addOverlay(myCompOverlay);
}
}
else {
for (var i = 0; i < result.length; i++) {
debugger
var name = result[i].Name; var borderData = "";
for (var j = 0; j < result[i].PointsList.length; j++) {
borderData = borderData + result[i].PointsList[j].Longitude + "," + result[i].PointsList[j].Latitude + ";";
}
var center = new BMap.Point(result[i].Longitude, result[i].Latitude);
var myCompOverlay = new ComplexCustomOverlay(center, result[i].Name, borderData); map.addOverlay(myCompOverlay);
}
}
} });
}
ComplexCustomOverlay.prototype = new BMap.Overlay();
ComplexCustomOverlay.prototype.initialize = function (map) {
this._map = map;
var div = this._div = document.createElement("div");
div.style.position = "absolute";
div.style.zIndex = BMap.Overlay.getZIndex(this._point.lat);
div.style.backgroundColor = "rgba(0, 172, 237, 0.88)";
div.style.border = "1px solid transparent";
div.style.borderRadius = "50%";
div.style.height = "60px";
div.style.width = "60px";
div.style.lineHeight = "18px";
div.style.cursor = "pointer";
div.setAttribute("data", this._point.lng + "," + this._point.lat);
div.setAttribute("data-border", this._data);
var p = this._span = document.createElement("p");
p.style.marginTop = "20px";
p.style.paddingLeft = "2px";
p.style.textAlign = "center";
p.style.fontSize = "14px";
p.style.color = "white"; div.appendChild(p);
p.appendChild(document.createTextNode(this._text));
var that = this; div.onmouseover = function () {
this.style.backgroundColor = "rgb(239, 58, 58)";
var zoom = map.getZoom();
if (zoom != 12 && zoom != 13) {
displayPolygon(div.getAttribute("data-border"));
}
//var poi = new BMap.Point(div.getAttribute("data").split(',')[0], div.getAttribute("data").split(',')[1]);
//map.panTo(poi); } div.onmouseout = function () {
this.style.backgroundColor = "rgba(0, 172, 237, 0.88)";
var zoom = map.getZoom();
if (zoom != 12 && zoom != 13) {
clearPolygon();
}
} map.getPanes().labelPane.appendChild(div); return div;
}
ComplexCustomOverlay.prototype.draw = function () {
var map = this._map;
var pixel = map.pointToOverlayPixel(this._point);
this._div.style.left = pixel.x - 28 + "px";
this._div.style.top = pixel.y - 28 + "px";
} function ComplexCustomOverlay(point, text, data) {
this._point = point;
this._text = text;
this._data = data;
}
var polygon;
function displayPolygon(arr) {
var list = arr.split(';');
var pnts = [];
for (var i = 0; i < list.length; i++) {
var point = new BMap.Point(list[i].split(',')[0], list[i].split(',')[1]);
pnts.push(point);
}
polygon = new BMap.Polygon(pnts, styleOptions); //创建多边形
//alert(polygon)
map.addOverlay(polygon); }
function clearPolygon() {
map.removeOverlay(polygon);
}
//覆盖物示例 end
实现效果: