bootstrap-select使用、relation-graph使用

 

bootstrap-select

这里要实现的是带有搜索功能的select框,

bootstrap 官网没有可以直接拿来用的。如下是官网给出的解释,带搜索功能的select需要自定义。

 

 

在网上找到了有自己用javascript+html+css生写的,代码量比较大,有两百多行,我拷贝了,试运行过,是没有问题,可以直接用的。

如下是我找的别人的原创博客地址。

https://blog.csdn.net/L333333333/article/details/102556003

我自己另外找了一个可以引用的组件,在特定的位置加上属性,即可实现bootstrap渲染的带搜索框的select标签,下面是我找的另一人的原创博客地址,

博客中的demo,直接copy可以运行,达到预期的效果,亲测有效。

https://blog.csdn.net/xb12369/article/details/50999265

 我自己在实际生产中,发现不能直接拿着人家的组件直接用,会有其他问题引出来,我已经解决了,所以写博客加以补充。

 

先介绍一下缘由,上面的两个例子里面,都能实现select框带模糊查询功能,因为是给出的demo示例,所以,option标签都是预先在页面上写死的,

但是,我们的实际生产中,select里面的option标签值,有的时候,是需要从后端接口拿到数据,然后才能进行渲染的,这个时候,就会牵扯到浏览器异步的问题。

我自己的这个项目里面,select里面是人员名单,而人员名单是需要从后端接口拿到数据,然后再用js进行渲染,这个时候,就会出现,Ajax调用后端接口,

还没有等Ajax拿到返回值结果,bootstrap-select组件就已经预加载了,而这个时候,option标签里面是没有数据信息的,所以,按照上面的用法,

bootstrap-select组件渲染的结果里面是没有数据的。

 

解决办法就是让他们变成同步的。

 

我自己的项目里面,window.onload里面是一个Ajax函数,这个Ajax函数是调用后端接口拿到返回值信息,然后在Ajax的回调函数里面用js去创建option标签,渲染页面。

我的解决办法就是,把触发bootstrap-select的jquery代码,放到我的Ajax回调函数里面,这样,在Ajax内部就完成了同步。

 

<link rel="stylesheet"
          href="{% static bootstrap %}bootstrap-3.3.7-dist/css/bootstrap.css"> <!-- 这里是我自己项目内部配置的本地的bootstrap的css引用库 -->

    <title>Title</title>
<!-- 这里是引用的cdn的jquery,jQuery的引用一定要放在最顶上,因为下面boostrap-select.js以及boostrap.js都需要建立在jQuery基础上 -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> 
   <!-- 这里是bootstrap-select css&js cdn引用 --> <script type="text/javascript" src="http://cdn.bootcss.com/bootstrap-select/2.0.0-beta1/js/bootstrap-select.js"></script> <link rel="stylesheet" type="text/css" href="http://cdn.bootcss.com/bootstrap-select/2.0.0-beta1/css/bootstrap-select.css"> <!-- 这里是我项目本地配置的bootstrap js引用库3.0 --> <script src="{% static bootstrap %}bootstrap-3.3.7-dist/js/bootstrap.js"></script>

<script>

//Ajax的前半截就不复制了,直接上Ajax回调函数部分,
xmlHttp.onreadystatechange = function (data) {
if (xmlHttp.readyState === 4 &&
(
(xmlHttp.status >= 200 && xmlHttp.status < 300)
|| xmlHttp.status === 304)
) {
    //拿到Ajax的回调函数,解析出来
    let response_data = data.srcElement.response;
    //get object type of data which backend transfer
    let parsed_data = JSON.parse(response_data).data;
    //拿到返回值之后,用js渲染标签
    show_option_data(parsed_data);
    //渲染完成之后,再触发bootstrap-select的组件
    $('.test-select').selectpicker();

  }
}

</script>

<!-- 如下是标签的属性绑定,这是单选的用法,如果需要多选,只需要在此基础上加上 multipule 即可-->
<select data-live-search="true" class="test-select"></select>

 

 

我自己把上面两个人的博客里面的代码,在自己博客里面备份一下,以防别人博客删除,没有线索了。

JavaScript+html+css

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>javascript+html+css--select-search</title>
  6     <style type="text/css">
  7 
  8         *{
  9             padding: 0;
 10             margin: 0;
 11         }
 12 
 13         body{
 14             width: 100vw;
 15             height: calc(100vh - 20px);
 16         }
 17 
 18         div.select select{
 19             display: none;
 20         }
 21 
 22         div.select-box{
 23             width: 200px;
 24             margin: 20px 20px;
 25         }
 26 
 27         div.select-head{
 28             position: relative;
 29             height: 30px;
 30             width: 100%;
 31             display: flex;
 32             border: solid 1px #000;
 33             align-items: center;
 34             cursor: pointer;
 35         }
 36 
 37         div.select-head span{
 38             font-size: 16px;
 39             margin-left: 5px;
 40             color: #AAA;
 41         }
 42 
 43         div.select-head span.fill{
 44             color: #000;
 45         }
 46 
 47         div.select-head i{
 48             position: absolute;
 49             height: 16px;
 50             width: 16px;
 51             right: 5px;
 52             background-image: url(./arrow.png);
 53             background-size: 16px auto;
 54         }
 55 
 56         div.select-body{
 57             display: none;
 58             width: 100%;
 59             border: solid 1px #000;
 60             border-top: none;
 61         }
 62 
 63         div.search-input{
 64             position: relative;
 65             height: 40px;
 66         }
 67 
 68         div.search-input input{
 69             height: 30px;
 70             width: 150px;
 71             margin: 5px 8px;
 72             text-indent: 10px;
 73             padding-right: 30px;
 74         }
 75 
 76         div.search-input i{
 77             position: absolute;
 78             display: block;
 79             height: 20px;
 80             width: 20px;
 81             top: 12px;
 82             right: 15px;
 83             background-image: url(./search-normal.png);
 84             background-size: 20px 20px;
 85             cursor: pointer;
 86         }
 87 
 88         div.search-input i:hover{
 89             background-image: url(./search-active.png);
 90         }
 91 
 92         div.value-body{
 93             max-height: 150px;
 94             overflow: auto;
 95         }
 96 
 97         div.value-body li{
 98             display: flex;
 99             height: 24px;
100             padding: 5px 5px;
101             font-size: 14px;
102             align-items: center;
103             cursor: pointer;
104         }
105 
106         div.value-body li:hover,li.active{
107             background-color: #F5F6FA;
108         }
109 
110         div.value-body li.none,div.none{
111             display: none;
112         }
113 
114         div.value-body div{
115             text-align: center;
116             height: 30px;
117             line-height: 30px;
118             color: #AAA;
119         }
120     </style>
121     <script type="text/javascript">
122         window.onload = function () {
123             //清空select的value
124             document.querySelector('div.select>select').value = ''
125 
126             /**
127              * 点击自定义的select框开启或收回选择框
128              */
129             document.querySelector('div.select-head').onclick = function () {
130                 //清空输入框内容
131                 document.querySelector('div.search-input>input').value = ''
132 
133                 document.querySelectorAll('div.value-body>li').forEach( function(element, index) {
134                     if (element.classList.contains('active')) {
135                         element.classList = 'active'
136                     }else {
137                         element.classList = ''
138                     }
139                 });
140 
141                 document.querySelector('div.value-body>div').classList = 'none'
142 
143                 var select_body = document.querySelector('div.select-body')
144                 if (select_body.style.display == 'block')
145                     select_body.style.display = 'none'
146                 else
147                     select_body.style.display = 'block'
148             };
149 
150             /**
151              * 点击空白处关闭select框
152              */
153             document.onclick = function (argument) {
154                 if(!argument.target.classList.contains('s')){
155                     var select_body = document.querySelector('div.select-body')
156                     if (select_body.style.display == 'block')
157                         select_body.style.display = 'none'
158                 }
159             }
160 
161             /**
162              * 自定义的select的选值功能
163              */
164             document.querySelectorAll('div.value-body>li').forEach( function(element, index) {
165                 element.onclick = function () {
166                     //初始化下样式
167                     document.querySelectorAll('div.value-body>li').forEach( function(element, index) {
168                         element.classList = ''
169                     });
170                     element.classList = 'active'
171                     //更新select框的value和自定义的select框的value
172                     var data_value = element.getAttribute('data-value')
173                     var select_head_span = document.querySelector('div.select-head>span')
174                     document.querySelector('div.select>select').value = data_value
175                     select_head_span.innerHTML = data_value
176                     if(!select_head_span.classList.contains('fill'))
177                         select_head_span.classList = 'fill'
178 
179                     //关闭select-body
180                     document.querySelector('div.select-body').style.display = 'none'
181                 }
182             });
183 
184             /**
185              * 搜素功能实现
186              */
187             document.querySelector('div.search-input>input').oninput = function () {
188                 var input_value = document.querySelector('div.search-input>input').value
189                 if(input_value == '') {
190                     document.querySelectorAll('div.value-body>li').forEach( function(element, index) {
191                         if (element.classList.contains('active')) {
192                             element.classList = 'active'
193                         }else {
194                             element.classList = ''
195                         }
196                     });
197                 }else{
198                     document.querySelectorAll('div.value-body>li').forEach( function(element, index) {
199                         if(element.getAttribute('data-value').indexOf(input_value) == -1){
200                                 if (element.classList.contains('active')) {
201                                     element.classList += ' none'
202                                 }else {
203                                     element.classList = 'none'
204                                 }
205                         }else {
206                             if(element.classList.contains('none')) {
207                                 document.querySelectorAll('div.value-body>li').forEach( function(element, index) {
208                                     if (element.classList.contains('active')) {
209                                         element.classList = 'active'
210                                     }else {
211                                         element.classList = ''
212                                     }
213                                 });
214                             }
215                         }
216                     });
217                 }
218                 //记一下结果数量
219                 var length = 0
220                 document.querySelectorAll('div.value-body>li').forEach( function(element, index) {
221                     if (!element.classList.contains('none')) length++
222                 });
223 
224                 if (length == 0) {
225                     document.querySelector('div.value-body>div').classList = ''
226                 }else{
227                     document.querySelector('div.value-body>div').classList = 'none'
228                 }
229             }
230         };
231     </script>
232 </head>
233 <body>
234     <div class="select">
235         <select name="select-name">
236             <option value="" disabled="true">请选择</option>
237             <option value="选择1">选择1</option>
238             <option value="选择2">选择2</option>
239             <option value="选择3">选择3</option>
240             <option value="选择4">选择4</option>
241             <option value="选择5">选择5</option>
242             <option value="选择6">选择6</option>
243             <option value="选择7">选择7</option>
244             <option value="选择8">选择8</option>
245             <option value="选择9">选择9</option>
246             <option value="选择10">选择10</option>
247         </select>
248         <div class="s select-box">
249             <div class="s select-head">
250                 <span class="s">请选择</span>
251                 <i class="s"></i>
252             </div>
253             <div class="s select-body">
254                 <div class="s search-input">
255                     <input class="s" type="text" placeholder="搜索">
256                     <i class="s"></i>
257                 </div>
258                 <div class="s value-body">
259                     <li data-value="选择1">选择1</li>
260                     <li data-value="选择2">选择2</li>
261                     <li data-value="选择3">选择3</li>
262                     <li data-value="选择4">选择4</li>
263                     <li data-value="选择5">选择5</li>
264                     <li data-value="选择6">选择6</li>
265                     <li data-value="选择7">选择7</li>
266                     <li data-value="选择8">选择8</li>
267                     <li data-value="选择9">选择9</li>
268                     <li data-value="选择10">选择10</li>
269                     <div class="none">暂无匹配选项</div>
270                 </div>
271             </div>
272         </div>
273     </div>
274 </body>
275 </html>
View Code

 

boostrap-select

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <title>jQuery bootstrap-select</title>
 5     <!-- set jquery cdn -->
 6     <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
 7 
 8     <!-- set bootstrap-select js and css -->
 9     <script type="text/javascript" src="http://cdn.bootcss.com/bootstrap-select/2.0.0-beta1/js/bootstrap-select.js"></script>
10     <link rel="stylesheet" type="text/css" href="http://cdn.bootcss.com/bootstrap-select/2.0.0-beta1/css/bootstrap-select.css">
11 
12     <!-- 3.0 cnd bootstrap css and js -->
13     <link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
14     <script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
15     <script type="text/javascript">
16         $(window).on('load', function () {
17 
18             $('.selectpicker').selectpicker();//one way set no params
19             //$('.selectpicker').selectpicker( //another way set params
20             // { 'selectedText': 'cat' }
21             // )
22 
23             // $('.selectpicker').selectpicker('hide');
24         });
25     </script>
26 </head>
27 <body>
28 <div>
29 
30     <label for="id_select">Test label YEag</label>
31     <select id="id_select" class="selectpicker bla bla bli"
32             multiple data-live-search="true">
33         <option>cow</option>
34         <option>bull</option>
35         <option class="get-class" disabled>ox</option>
36         <optgroup label="test" data-subtext="another test" data-icon="icon-ok">
37             <option>ASD</option>
38             <option selected>Bla</option>
39             <option>Ble</option>
40         </optgroup>
41     </select>
42 
43     <div class="container">
44         <form class="form-horizontal" role="form">
45             <div class="form-group">
46                 <label for="bs3Select" class="col-lg-2 control-label">Test bootstrap 3 form</label>
47                 <div class="col-lg-10">
48                     <select id="bs3Select" class="selectpicker show-tick form-control" multiple data-live-search="true">
49                         <option>cow</option>
50                         <option>bull</option>
51                         <option class="get-class" disabled>ox</option>
52                         <optgroup label="test" data-subtext="another test" data-icon="icon-ok">
53                             <option>ASD</option>
54                             <option selected>Bla</option>
55                             <option>Ble</option>
56                         </optgroup>
57                     </select>
58                 </div>
59               </div>
60         </form>
61     </div>
62     </div>
63 
64 </body>
65 </html>
View Code

 

relation-graph

这里是relation-graph,vue插件实际使用示例:

.vue文件,可以放到vue项目直接运行

<template>
  <div>
    <h3>hi relation-graph</h3>
    <div>
      <label>暂仅支持PCS-ID查询</label>
      <input type="text" v-model="pcsID">
      <button type="button" @click="doClick">submit</button>
    </div>
    <div v-loading="g_loading" style="margin-top:50px;width: calc(100% - 10px);height:calc(100vh - 140px);">
      <SeeksRelationGraph ref="seeksRelationGraph" :options="graphOptions" :on-node-expand="onNodeExpand"
                          :on-node-collapse="onNodeCollapse">
      </SeeksRelationGraph>
    </div>
    <el-button type="success" class="c-show-code-button">
      <el-link href="https://github.com/seeksdream/relation-graph/blob/master/doc/demo/Demo4ExpandGradually.vue"
               target="_blank" style="color: #ffffff;">查看代码
      </el-link>
    </el-button>
  </div>
</template>

<script>
  import SeeksRelationGraph from 'relation-graph'

  import {ajaxGetNodeData} from "../static_frontend/js/basic_call_func";  //调用自己封装的javascript写的ajax函数

  export default {
    name: 'GraphRelationTest',
    components: {SeeksRelationGraph},
    data() {
      return {
        g_loading: true,
        demoname: '---',
        graphOptions: {
          'backgrounImage': 'http://ai-mark.cn/images/ai-mark-desc.png',
          'backgrounImageNoRepeat': true,
          'layouts': [
            {
              'label': '中心',
              'layoutName': 'tree',
              'layoutClassName': 'seeks-layout-center',
              'defaultJunctionPoint': 'border',
              'defaultNodeShape': 0,
              'defaultLineShape': 1,
              'from': 'left',
              'max_per_width': '300',
              'min_per_height': '40'
            }
          ],
          'defaultLineMarker': {
            'markerWidth': 12,
            'markerHeight': 12,
            'refX': 6,
            'refY': 6,
            'data': 'M2,2 L10,6 L2,10 L6,6 L2,2'
          },
          "defaultExpandHolderPosition": "right",
          'defaultNodeShape': 1,
          'defaultNodeWidth': '100',
          'defaultLineShape': 4,
          'defaultJunctionPoint': 'lr',
          'defaultNodeBorderWidth': 0,
          'defaultLineColor': 'rgba(0, 186, 189, 1)',
          'defaultNodeColor': 'rgba(0, 206, 209, 1)'
        }
      }
    },
    created() {
    },
    mounted(){},
    methods: {
      setGraphData(__graph_json_data) {
        // 使用要点:通过节点属性expandHolderPosition: 'right' 和 expanded: false 可以让节点在没有子节点的情况下展示一个"展开"按钮
        //         通过onNodeExpand事件监听节点,在被展开的时候有选择的去从后台获取数据,如果已经从后台加载过数据,则让当前图谱根据当前的节点重新布局
        this.$refs.seeksRelationGraph.setJsonData(__graph_json_data, (seeksRGGraph) => {
          // 这些写上当图谱初始化完成后需要执行的代码
          // 获取根节点的子节点,即可获得图谱第一层中的节点
          var level_1_nodes = seeksRGGraph.getNodeById(__graph_json_data.rootId).lot.childs
          level_1_nodes.forEach(thisLevel1Node => {
            this.applyCollapseStyle2Node(thisLevel1Node)
          })
          this.$refs.seeksRelationGraph.refresh()
        })
      },
      applyCollapseStyle2Node(_node) { // _node的子节点将被隐藏,同时让_node右侧显示一个加号,点击后可以展开子节点
        if (_node.lot.childs.length > 0) {
          _node.lot.childs.forEach(thisChildNode => {
            thisChildNode.isShow = false
            this.applyCollapseStyle2Node(thisChildNode)
          })
          _node.expanded = false
          _node.expandHolderPosition = 'right'
        }
      },
      onNodeCollapse(node, e) {
        // console.log('onNodeCollapse:', node)
        // 当有一些节点被显示或隐藏起来时,会让图谱看着很难看,需要布局器重新为节点分配位置,所以这里需要调用refresh方法来重新布局
        this.$refs.seeksRelationGraph.refresh()
      },
      onNodeExpand(node, e) {
        // 当有一些节点被显示或隐藏起来时,会让图谱看着很难看,需要布局器重新为节点分配位置,所以这里需要调用refresh方法来重新布局
        // console.log('onNodeExpand:', node)
        this.$refs.seeksRelationGraph.refresh()
      },
      doClick() {
        console.log("this-object>>>", this, typeof(this))
        //跟标签绑定的触发函数
        let pcs_id = this.pcsID; // v-model是标签属性,在标签中设置它之后,methods下面的每个函数里面都可以通过this.属性值取标签值,
        // 比如v-model='pcsID',取值就用this.pcsID==document.getElementById("pcsID").value
        // 这里要跟ajax的返回值挂上钩,从ajax拿到后端返回值数据,拼接到下面的nodes、links里面
        ajaxGetNodeData(this.setGraphData, pcs_id)
      }
    }
  }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

 

补充ajax封装的函数:

export function ajaxGetNodeData(call_back_func, id_value=null) {
  //这里封装ajax函数,把ajax请求的回调函数里面,传入加载渲染节点的插件调用方法
  let xmlHttp = new XMLHttpRequest();
  xmlHttp.open("POST", "http://localhost:8000/api/v1/graph_test", true);
  xmlHttp.setRequestHeader("Access-Control-Allow-Origin", "*")
  xmlHttp.setRequestHeader(
    "Content-Type", "application/json;charset=UTF-8"
  );
  let post_data = JSON.stringify({
    "name": id_value,
  });
  xmlHttp.send(post_data);
  xmlHttp.onreadystatechange = function (data) {
    if (xmlHttp.readyState === 4 &&
      (
        (xmlHttp.status >= 200 && xmlHttp.status < 300)
        || xmlHttp.status === 304)
    ) {
      let response_data = data.target.response;
      //get object type of data which backend transfor
      let parsed_data = JSON.parse(response_data);
      var __graph_json_data = parsed_data.data;
      //在success回调函数中,拿到后端请求得到的数据,启动插件方法,把数据传入进去,渲染到页面
      call_back_func(__graph_json_data);
      if (parsed_data.error != null) {
        alert(parsed_data.info)
      }
    }
    //get ajax error response
    xmlHttp.onerror = function () {
      alert("got error function");
      console.log(xmlHttp.response);
      console.log(xmlHttp.responseXML);
      console.log(xmlHttp.getAllResponseHeaders());
    };
  };
}

 

posted @ 2021-05-21 15:34  dream-子皿  阅读(1011)  评论(0编辑  收藏  举报