D3 縱向組織結構樹

本文基于專注于D3的呂之華前輩分享的樹狀圖畫法來寫縱向組織結構樹圖

第十五章中樹狀圖的樣式為:


我們可以進行拓展,寫出公司項目更為常用的豎向組織結構樹,效果圖如下:



主要需要進行的工作為:

  1. 將橫縱坐標對換,變成縱向樹狀圖
  2. 將曲線更改為折線
  3. 將圓圈節點更改為矩形節點,顯示的文字位置也需要進行相應切換

原樹狀圖代碼為:

<html>
<head>
    <meta charset="utf-8">
    <title>樹狀圖</title>
    <style>
        .node circle {
            fill: #fff;
            stroke: steelblue;
            stroke-width: 1.5px;
        }

        .node {
            font: 12px sans-serif;
        }

        .link {
            fill: none;
            stroke: #ccc;
            stroke-width: 1.5px;
        }
    </style>
</head>

<body>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>
        var width = 500,
            height = 500;
        var root = {
            "name": "中國",
            "children": [{
                    "name": "浙江",
                    "children": [{
                            "name": "杭州"
                        },
                        {
                            "name": "寧波"
                        },
                        {
                            "name": "溫州"
                        },
                        {
                            "name": "紹興"
                        }
                    ]
                },

                {
                    "name": "廣西",
                    "children": [{
                            "name": "桂林",
                            "children": [{
                                    "name": "秀峰區"
                                },
                                {
                                    "name": "疊彩區"
                                },
                                {
                                    "name": "象山區"
                                },
                                {
                                    "name": "七星區"
                                }
                            ]
                        },
                        {
                            "name": "南寧"
                        },
                        {
                            "name": "柳州"
                        },
                        {
                            "name": "防城港"
                        }
                    ]
                },

                {
                    "name": "黑龍江",
                    "children": [{
                            "name": "哈爾濱"
                        },
                        {
                            "name": "齊齊哈爾"
                        },
                        {
                            "name": "牡丹江"
                        },
                        {
                            "name": "大慶"
                        }
                    ]
                },

                {
                    "name": "新疆",
                    "children": [{
                            "name": "烏魯木齊"
                        },
                        {
                            "name": "克拉瑪依"
                        },
                        {
                            "name": "吐魯番"
                        },
                        {
                            "name": "哈密"
                        }
                    ]
                }
            ]
        };
        var tree = d3.layout.tree()
            .size([width, height - 200])
            .separation(function (a, b) {
                return (a.parent == b.parent ? 1 : 2);
            });

        var diagonal = d3.svg.diagonal()
            .projection(function (d) {
                return [d.y, d.x];
            });

        var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height)
            .append("g")
            .attr("transform", "translate(40,0)");




        var nodes = tree.nodes(root);
        var links = tree.links(nodes);

        console.log(nodes);
        console.log(links);

        var link = svg.selectAll(".link")
            .data(links)
            .enter()
            .append("path")
            .attr("class", "link")
            .attr("d", diagonal);

        var node = svg.selectAll(".node")
            .data(nodes)
            .enter()
            .append("g")
            .attr("class", "node")
            .attr("transform", function (d) {
                return "translate(" + d.y + "," + d.x + ")";
            })

        node.append("circle")
            .attr("r", 4.5);

        node.append("text")
            .attr("dx", function (d) {
                return d.children ? -8 : 8;
            })
            .attr("dy", 3)
            .style("text-anchor", function (d) {
                return d.children ? "end" : "start";
            })
            .text(function (d) {
                return d.name;
            });
    </script>
</body>
</html>
  1. 橫向樹狀圖更改為縱向無非就是橫縱坐標相關配置進行對調,修改如下:
        var width = 1200 // edited

        var diagonal = d3.svg.diagonal()
            .projection(function (d) {
                return [d.x, d.y];  // edited
            });
        var svg = d3.select("body").append("svg")
            .attr("width", width + 80) // 畫布擴大,防止邊緣文字被遮擋
            .attr("height", height)
            .append("g")
            .attr("transform", "translate(40,40)"); // 將圖整體下移,以防止頂部節點被遮擋

        var node = svg.selectAll(".node")
            .data(nodes)
            .enter()
            .append("g")
            .attr("class", "node")
            .attr("transform", function (d) {
                return "translate(" + d.x + "," + d.y + ")"; // edited
            })

顯示效果如下


  1. 將曲線更改為折線:
// 定義矩形的寬高,折線據此確定橫縱坐標
var boxWidth = 65, boxHeight = 40;
/*        var link = svg.selectAll(".link")
            .data(links)
            .enter()
            .append("path")
            .attr("class", "link")
            .attr("d", diagonal);
*/
        drawLine();
        // 將曲線換為折線
        function drawLine() {
            var link = svg.selectAll("path.link")

                // The function we are passing provides d3 with an id
                // so that it can track when data is being added and removed.
                // This is not necessary if the tree will only be drawn once
                // as in the basic example.
                .data(links);

            // Add new links    
            link.enter().append("path")
                .attr("class", "link");

            // Remove any links we don't need anymore
            // if part of the tree was collapsed
            link.exit().remove();

            // Update the links positions (old and new)
            link.attr("d", elbow);

            function elbow(d) {
                let sourceX = d.source.x,
                    sourceY = d.source.y + boxHeight,
                    targetX = d.target.x,
                    targetY = d.target.y;

                return "M" + sourceX + "," + sourceY +
                    "V" + ((targetY - sourceY) / 2 + sourceY) +
                    "H" + targetX +
                    "V" + targetY;

            }
        }

顯示效果如圖:


  1. 將圓圈節點更改為矩形節點:
        // 圓形節點與對應文字
        // node.append("circle")
        //  .attr("r", 4.5);

        // node.append("text")
        //  .attr("dx", function (d) {
        //      return d.children ? -8 : 8;
        //  })
        //  .attr("dy", 3)
        //  .style("text-anchor", function (d) {
        //      return d.children ? "end" : "start";
        //  })
        //  .text(function (d) {
        //      return d.name;
        //  });
        // 繪制矩形與文字
        drawRect();

        function drawRect() {
            node.append("rect")
                .attr('y', 0)
                .attr('x', function (d) {
                    return d.depth !== 2 ? -(boxWidth / 2) : -(boxHeight / 2)
                })
                .attr('width', function (d) {
                    return d.depth !== 2 ? boxWidth : boxHeight;
                })
                .attr('height', function (d) {
                    return d.depth !== 2 ? boxHeight : boxWidth;
                })
                // 矩形背景色以及邊框顏色寬度
                .attr('fill', '#fff')
                .attr('stroke', 'steelblue')
                .attr('strokeWidth', '1px')
                .on('click', function (evt) {
                    console.log(evt); // 顯示所點擊節點數據
                });

            // Draw the person's name and position it inside the box
            node.append("text")
                .attr('y', function (d) {
                    return d.depth !== 2 ? boxHeight / 2 + 5 : 0;
                })
                // .attr('rotate', function (d) { //顯示豎直顯示中文時rotate為0,英文-90
                //     return 0;
                // })
                .attr('style', function (d) {
                    return d.depth !== 2 ? '' : "writing-mode: tb;letter-spacing:0px";
                })
                .attr("text-anchor", function (d) {
                    return d.depth !== 2 ? 'middle' : "start";
                })
                .text(function (d) {
                    return d.name;
                });
        }

顯示效果如圖:



再增加放大放小的功能

        // 用來拖拽圖以及擴大縮放
        var zoom = d3.behavior.zoom()
                .scaleExtent([.1, 1])
                .on('zoom', function () {
                        svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
                });
        var svg = d3.select("body").append("svg")
            .attr("width", width + 80) // 畫布擴大,防止邊緣文字被遮擋
            .attr("height", height)
            .append("g")
            .call(zoom) // 相當于zoom(svg)
            .attr("transform", "translate(40,40)"); // 將圖整體下移,以防止頂部節點被遮擋

至此成功將橫向樹狀圖成功轉換為縱向組織結構樹圖
完整代碼如下:

<!Doctype html>
<head>
    <meta charset="utf-8">
    <title>樹狀圖</title>
    <style>
        .node circle {
            fill: #fff;
            stroke: steelblue;
            stroke-width: 1.5px;
        }

        .node {
            font: 12px sans-serif;
        }

        .link {
            fill: none;
            stroke: #ccc;
            stroke-width: 1.5px;
        }
    </style>
</head>

<body>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <!-- 縱向樹狀圖 -->
    <script>
        var width = 1200,
            height = 500,
            boxWidth = 65,
            boxHeight = 40;
        var root = {
            "name": "中國",
            "children": [{
                    "name": "浙江",
                    "children": [{
                            "name": "杭州"
                        },
                        {
                            "name": "寧波"
                        },
                        {
                            "name": "溫州"
                        },
                        {
                            "name": "紹興"
                        }
                    ]
                },

                {
                    "name": "廣西",
                    "children": [{
                            "name": "桂林",
                            "children": [{
                                    "name": "秀峰區"
                                },
                                {
                                    "name": "疊彩區"
                                },
                                {
                                    "name": "象山區"
                                },
                                {
                                    "name": "七星區"
                                }
                            ]
                        },
                        {
                            "name": "南寧"
                        },
                        {
                            "name": "柳州"
                        },
                        {
                            "name": "防城港"
                        }
                    ]
                },

                {
                    "name": "黑龍江",
                    "children": [{
                            "name": "哈爾濱"
                        },
                        {
                            "name": "齊齊哈爾"
                        },
                        {
                            "name": "牡丹江"
                        },
                        {
                            "name": "大慶"
                        }
                    ]
                },

                {
                    "name": "新疆",
                    "children": [{
                            "name": "烏魯木齊"
                        },
                        {
                            "name": "克拉瑪依"
                        },
                        {
                            "name": "吐魯番"
                        },
                        {
                            "name": "哈密"
                        }
                    ]
                }
            ]
        };
        var tree = d3.layout.tree()
            .size([width, height - 200])
            .separation(function (a, b) {
                return (a.parent == b.parent ? 1 : 2);
            });

        var diagonal = d3.svg.diagonal()
            .projection(function (d) {
                return [d.x, d.y]; // edited
            });

        // 用來拖拽圖以及擴大縮放
        var zoom = d3.behavior.zoom()
                .scaleExtent([.1, 1])
                .on('zoom', function () {
                        svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
                });
        var svg = d3.select("body").append("svg")
            .attr("width", width + 80) // 畫布擴大,防止邊緣文字被遮擋
            .attr("height", height)
            .append("g")
            .call(zoom) // 相當于zoom(svg)
            .attr("transform", "translate(40,40)"); // 將圖整體下移,以防止頂部節點被遮擋


        var nodes = tree.nodes(root);
        var links = tree.links(nodes);

        console.log(nodes);
        console.log(links);

        // var link = svg.selectAll(".link")
        //  .data(links)
        //  .enter()
        //  .append("path")
        //  .attr("class", "link")
        //  .attr("d", diagonal);

        drawLine();
        // 將曲線換為折線
        function drawLine() {
            var link = svg.selectAll("path.link")

                // The function we are passing provides d3 with an id
                // so that it can track when data is being added and removed.
                // This is not necessary if the tree will only be drawn once
                // as in the basic example.
                .data(links);

            // Add new links    
            link.enter().append("path")
                .attr("class", "link");

            // Remove any links we don't need anymore
            // if part of the tree was collapsed
            link.exit().remove();

            // Update the links positions (old and new)
            link.attr("d", elbow);

            function elbow(d) {
                let sourceX = d.source.x,
                    sourceY = d.source.y + boxHeight,
                    targetX = d.target.x,
                    targetY = d.target.y;

                return "M" + sourceX + "," + sourceY +
                    "V" + ((targetY - sourceY) / 2 + sourceY) +
                    "H" + targetX +
                    "V" + targetY;

            }
        }
        var node = svg.selectAll(".node")
            .data(nodes)
            .enter()
            .append("g")
            .attr("class", "node")
            .attr("transform", function (d) {
                return "translate(" + d.x + "," + d.y + ")"; // edited
            })

        // 圓形節點與對應文字
        // node.append("circle")
        //  .attr("r", 4.5);

        // node.append("text")
        //  .attr("dx", function (d) {
        //      return d.children ? -8 : 8;
        //  })
        //  .attr("dy", 3)
        //  .style("text-anchor", function (d) {
        //      return d.children ? "end" : "start";
        //  })
        //  .text(function (d) {
        //      return d.name;
        //  });
        // 繪制矩形與文字
        drawRect();

        function drawRect() {
            node.append("rect")
                .attr('y', 0)
                .attr('x', function (d) {
                    return d.depth !== 2 ? -(boxWidth / 2) : -(boxHeight / 2)
                })
                .attr('width', function (d) {
                    return d.depth !== 2 ? boxWidth : boxHeight;
                })
                .attr('height', function (d) {
                    return d.depth !== 2 ? boxHeight : boxWidth;
                })
                // 矩形背景色以及邊框顏色寬度
                .attr('fill', '#fff')
                .attr('stroke', 'steelblue')
                .attr('strokeWidth', '1px')
                .on('click', function (evt) {
                    console.log(evt); // 顯示所點擊節點數據
                });

            // Draw the person's name and position it inside the box
            node.append("text")
                .attr('y', function (d) {
                    return d.depth !== 2 ? boxHeight / 2 + 5 : 0;
                })
                // .attr('rotate', function (d) { //顯示豎直顯示中文時rotate為0,英文-90
                //     return 0;
                // })
                .attr('style', function (d) {
                    return d.depth !== 2 ? '' : "writing-mode: tb;letter-spacing:0px";
                })
                .attr("text-anchor", function (d) {
                    return d.depth !== 2 ? 'middle' : "start";
                })
                .text(function (d) {
                    return d.name;
                });
        }
    </script>
</body>

</html>

現在我們來進行代碼優化,將代碼封裝到StructureGraph類中,相關節點與連線的渲染畫法代碼邏輯綁定到此類的原型上,最后通過StructureGraph的render方法渲染出來縱向組織結構樹圖,代碼如下:

<html>

<head>
    <meta charset="utf-8">
    <title>樹狀圖</title>
    <style>
        .node circle {
            fill: #fff;
            stroke: steelblue;
            stroke-width: 1.5px;
        }

        .node {
            font: 12px sans-serif;
        }

        .link {
            fill: none;
            stroke: #ccc;
            stroke-width: 1.5px;
        }
    </style>
</head>

<body>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>
        var options = {
            width: 1200,
            height: 500,
            boxWidth: 65,
            boxHeight: 40
        }
        var city_tree = {
            "name": "中國",
            "children": [{
                    "name": "浙江",
                    "children": [{
                            "name": "杭州"
                        },
                        {
                            "name": "寧波"
                        },
                        {
                            "name": "溫州"
                        },
                        {
                            "name": "紹興"
                        }
                    ]
                },

                {
                    "name": "廣西",
                    "children": [{
                            "name": "桂林",
                            "children": [{
                                    "name": "秀峰區"
                                },
                                {
                                    "name": "疊彩區"
                                },
                                {
                                    "name": "象山區"
                                },
                                {
                                    "name": "七星區"
                                }
                            ]
                        },
                        {
                            "name": "南寧"
                        },
                        {
                            "name": "柳州"
                        },
                        {
                            "name": "防城港"
                        }
                    ]
                },

                {
                    "name": "黑龍江",
                    "children": [{
                            "name": "哈爾濱"
                        },
                        {
                            "name": "齊齊哈爾"
                        },
                        {
                            "name": "牡丹江"
                        },
                        {
                            "name": "大慶"
                        }
                    ]
                },

                {
                    "name": "新疆",
                    "children": [{
                            "name": "烏魯木齊"
                        },
                        {
                            "name": "克拉瑪依"
                        },
                        {
                            "name": "吐魯番"
                        },
                        {
                            "name": "哈密"
                        }
                    ]
                }
            ]
        }

        // 縱向樹狀圖類
        var StructureGraph = function () {
            // 布局
            this.tree = d3.layout.tree()
                .size([options.width, options.height - 200])
                .separation(function (a, b) {
                    return (a.parent == b.parent ? 1 : 2);
                });

            this.diagonal = d3.svg.diagonal()
                .projection(function (d) {
                    return [d.x, d.y];
                });

            // 用來拖拽圖以及擴大縮放
            let zoom = d3.behavior.zoom()
                .scaleExtent([.1, 1])
                .on('zoom',  () => {
                    this.svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
                });
            this.svg = d3.select("body").append("svg")
                .attr("width", options.width + 80)
                .attr("height", options.height)
                .call(zoom)
                .append("g")
                .attr("transform", "translate(40,40)");
        }

        // 開始渲染節點與連線
        StructureGraph.prototype.render = function (source) {
            this.renderLinks(source);
            this.renderNodes(source);
            return this;
        }

        // 渲染節點
        StructureGraph.prototype.renderNodes = function (source) {
            var _this = this;
            this.node = this.svg.selectAll(".node")
                .data(this.nodes)
                .enter()
                .append("g")
                .attr("class", "node")
                .attr("strokeWidth", 100)
                .attr("transform", function (d) {
                    return "translate(" + d.x + "," + d.y + ")";
                })
            // 繪制矩形與文字
            drawRect();

            function drawRect() {
                _this.node.append("rect")
                    .attr('y', 0)
                    .attr('x', function (d) {
                        return d.depth !== 2 ? -(options.boxWidth / 2) : -(options.boxHeight / 2)
                    })
                    .attr('width', function (d) {
                        return d.depth !== 2 ? options.boxWidth : options.boxHeight;
                    })
                    .attr('height', function (d) {
                        return d.depth !== 2 ? options.boxHeight : options.boxWidth;
                    })
                    // 矩形背景色以及邊框顏色寬度
                    .attr('fill', '#fff')
                    .attr('stroke', 'steelblue')
                    .attr('strokeWidth', '1px')
                    .on('click', function (evt) {
                        console.log(evt); // 顯示所點擊節點數據
                    });

                // Draw the person's name and position it inside the box
                _this.node.append("text")
                    .attr('y', function (d) {
                        return d.depth !== 2 ? options.boxHeight / 2 + 5 : 0;
                    })
                    // .attr('rotate', function (d) { //顯示豎直顯示中文時rotate為0,英文-90
                    //     return 0;
                    // })
                    .attr('style', function (d) {
                        return d.depth !== 2 ? '' : "writing-mode: tb;letter-spacing:0px";
                    })
                    .attr("text-anchor", function (d) {
                        return d.depth !== 2 ? 'middle' : "start";
                    })
                    .text(function (d) {
                        return d.name;
                    });
            }

        }

        // 渲染連線
        StructureGraph.prototype.renderLinks = function (source) {
            var _this = this;
            this.nodes = this.tree.nodes(source);
            
            this.links = this.tree.links(this.nodes);
   
            drawLine();
            // 將曲線換為折線
            function drawLine() {
                var link = _this.svg.selectAll("path.link")

                    // The function we are passing provides d3 with an id
                    // so that it can track when data is being added and removed.
                    // This is not necessary if the tree will only be drawn once
                    // as in the basic example.
                    .data(_this.links);

                // Add new links    
                link.enter().append("path")
                    .attr("class", "link");

                // Remove any links we don't need anymore
                // if part of the tree was collapsed
                link.exit().remove();

                // Update the links positions (old and new)
                link.attr("d", elbow);

                function elbow(d) {
                    let sourceX = d.source.x,
                        sourceY = d.source.y + options.boxHeight,
                        targetX = d.target.x,
                        targetY = d.target.y;

                    return "M" + sourceX + "," + sourceY +
                        "V" + ((targetY - sourceY) / 2 + sourceY) +
                        "H" + targetX +
                        "V" + targetY;

                }
            }
        }

        // 初始化實例。與jquery配合使用可以通過將下面兩行代碼放到$.fn.structure = (){}中,增加自定義插件
        var ins = new StructureGraph();
        ins.render(city_tree);
    </script>

</body>

</html>

這樣我們代碼就顯得有條理多了,維護性與可用性也大大提高。在線觀看demo

總結

學習D3的時間才幾天沒研究透徹,有些更高級的功能比如點擊節點的收縮以及動畫效果還沒研究,后期持續更新。由于入門不久,有需要糾正以及優化的地方歡迎評論提出~

參考文獻

樹圖的展開和折疊: https://blog.csdn.net/qq_26562641/article/details/77480767
組織結構樹:https://blog.csdn.net/u014324940/article/details/81206364
D3 入門教程:http://wiki.jikexueyuan.com/project/d3wiki/introduction.html
D3官方網站:http://d3js.org

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容

  • 關于Mongodb的全面總結 MongoDB的內部構造《MongoDB The Definitive Guide》...
    中v中閱讀 32,001評論 2 89
  • 基于樹實現的數據結構,具有兩個核心特征: 邏輯結構:數據元素之間具有層次關系; 數據運算:操作方法具有Log級的平...
    yhthu閱讀 4,303評論 1 5
  • 那就是認真寫字呀哈哈哈 昨天答應大家今天PO我寫的字,在這里跟大家說聲:久等啦! 寫完后我又特意找寫字好看的同學幫...
    一罐萌丸醬閱讀 306評論 0 2
  • 人活一世,心態很重要 無論此刻身處順境逆境 都要放平心態 不能被黑暗吞沒 要學會自我調節 多想想父母 就覺得又有動...
    桃桃之妖妖閱讀 316評論 0 0
  • 并無稀奇事情,下午很困,被冰心說了
    青玄子閱讀 144評論 0 0