bootstrap-select使用、relation-graph使用

2023-03-07,,

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>

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>

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());
};
};
}

bootstrap-select使用、relation-graph使用的相关教程结束。

《bootstrap-select使用、relation-graph使用.doc》

下载本文的Word格式文档,以方便收藏与打印。