当前位置: 首页 > news >正文

昆明网站建设公司哪家好百度平台

昆明网站建设公司哪家好,百度平台,制作网页推广宣传,手表到哪个网站买目录 一、selectedKeys与onSelect 官方文档 代码演示 onSelect 注意事项 二、expandedKeys与onExpand 官方文档 代码演示 onExpand 注意事项 三、loadedKeys与onLoad和onExpand 官方文档 代码演示 onExpand与onLoad#xff1a;​ 注意事项 四、loadData …目录 一、selectedKeys与onSelect 官方文档 代码演示 onSelect  注意事项  二、expandedKeys与onExpand 官方文档 代码演示 onExpand  注意事项  三、loadedKeys与onLoad和onExpand 官方文档 代码演示 onExpand与onLoad​ 注意事项  四、loadData 官方文档 代码演示 loadData  注意事项  五、树节点局部节点刷新 实现思路  代码演示 六、递归获取与修改数据 获取数据 修改数据 七、总结 最近一周都在忙关于文件管理的东西从提出这个需求到目前实现为止已经快一周的时间了。从最开始的找插件然后发现没有插件可以用再到打算自己手撸一个发现手写树状图过于困难且因为技术力的原因估计会留下很多坑。所以在经过多方考虑以后觉得还是通过 antd-tree手动控制的方式去实现一个文件管理页面。 下面我将着重讲解我在使用antd-tree组件时遇到的各种苦难已经官方文档中方法属性的应用。 一、selectedKeys与onSelect 官方文档 参数说明类型版本selectedKeys受控设置选中的树节点string[]onSelect点击树节点触发function(selectedKeys, e:{selected: bool, selectedNodes, node, event}) 代码演示 onSelect  形参 selectedKeys 代表当前选中的树节点的key值。获取的值的格式为[ key ]。可以通过selectedKeys[0]取值。 info: 当前选择的树节点的信息。可以通过info.selectedNodes.props.dataRef.children来获取当前节点的子节点。 注意事项  这里需要注意的是selectedKeys是一个数组类型。有且只有一个当前选中的节点key。一旦点击其他节点数组内的值就会被替换。 如果树组件设置了selectedKeys这个属性那么需要在onSelect函数执行时将值赋给该属性。 二、expandedKeys与onExpand 官方文档 参数说明类型默认值版本expandedKeys受控展开指定的树节点string[][]onExpand展开/收起节点时触发function(expandedKeys, {expanded: bool, node})- 代码演示 onExpand  形参 expandedKeys 代表当前打开的树节点的key值。 info: 当前打开的树节点的信息。 注意事项  这里需要注意的是expandedKeys也是一个数组的格式但它与selectedKeys的区别是selectedKeys始终是一个长度为0或1的数组而expandedKeys则是包含所有被打开的树节点的key值。 三、loadedKeys与onLoad和onExpand 官方文档 参数说明类型默认值版本loadedKeys受控已经加载的节点需要配合 loadData 使用string[][]3.7.0onExpand展开/收起节点时触发function(expandedKeys, {expanded: bool, node})-onLoad节点加载完毕时触发function(loadedKeys, {event, node})-3.7.0 代码演示 onExpand与onLoad 形参 loadedKeys已经完成加载的树节点的key是一个数组的数据类型。 注意事项  这里需要注意的是loadedKeys是一个数组数据类型且可以存放多个key。一旦被加载过以后无论怎么点击都不会再触发重新刷新重新加载了。如果想让其刷新请移步至节点刷新。 四、loadData 官方文档 参数说明类型默认值版本loadData异步加载数据function(node)-loadedKeys受控已经加载的节点需要配合 loadData 使用string[][]3.7.0treeDatatreeNodes 数据如果设置则不需要手动构造 TreeNode 节点key 在整个树范围内唯一array\{key, title, children, [disabled, selectable]}- 代码演示 loadData  形参 treeNode 要加载的树节点的信息。 注意事项  这里需要注意的是如果你的树节点是通过点击以后再加载子节点那么对于后端的数据格式返回可能就有一些要求了。比如 title 与 isLeaf 等。当然也可以在loadData中自行设置。 loadData中代码的大概流程就是先判断 treeNode 是否有 children这个属性注意是是否有这个属性如果有这个属性但这个属性为空数组在执行中也会判定为true从而不会执行更新操作而是直接return出去。 五、树节点局部节点刷新 实现思路  因为tree的机制问题当key节点加载过以后该节点将不会再被重新加载因此如果我上传了一个文件实际上服务器上已经有文件了但因为节点刷新问题该节点没有重新刷新我就看不到对应的节点文件。因此需要进行局部节点刷新。 满足节点刷新的条件有这几个。 1. loadedKeys中移除该节点的key值和其子孙节点的key值2. treeData中将该节点的children属性删除3. expandedKeys中移除A节点下的所有子孙节点的key值完成这三点以后再将selectedKeys选取到该节点 并将以上数据重新赋值给对应的属性即可完成节点刷新操作。 代码演示 updateTree () {const { selectedKeys , expandedKeys, loadedKeys, treeData } this.state// 获取新的expandedKeys数组不包含该节点及子节点const newExpandedKeys expandedKeys.filter(item {return item.indexOf(selectedKeys[0]) -1})// 获取新的loadedKeys数组不包含该节点及子节点const newLoadedKeys loadedKeys.filter(item {return item.indexOf(selectedKeys[0]) -1})const newTreedata treeDatathis.setState({expandedKeys: [...newExpandedKeys,...[${selectedKeys[0]}]],loadedKeys: [...newLoadedKeys],treeData: this.removeShowData(newTreedata),selectedKeys: [${selectedKeys[0]}],})}// 获取新的treeData数据removeShowData (datas) {const { selectedKeys } this.stateconst newData datas;function setGrayNode(data){ //遍历树 获取id数组for(var i0;idata.length;i){if(data[i].key selectedKeys[0]){// 如果某一个节点是禁用的它的所有子节点都应该禁用delete data[i].childrencontinue;} else {if(data[i].children){// 如果当前节点有子节点就递归调用一次setGrayNode(data[i].children);}}}}setGrayNode(newData)return newData;} 这里需要注意的是 expandedKeys 虽然删除了当前节点但要想操作通顺需要再次手动赋值将该节点打开并获取新的数据。这样就省去了用户需要再次点击节点的尴尬情况。 六、递归获取与修改数据 因为这是一个树状图数据结构也稍微复杂一些所以获取数据时难免需要通过递归拿取数据。所以需要一个递归函数取实现数据的拿取。 获取数据 //递归获取Showdata数据 getShowData (datas) {const { selectedKeys } this.statedatas.map(item {const { key, children } itemif (key selectedKeys[0]) {//符合条件this.setState({showData: datas})return}//如果有孩子再次调用自己将孩子传进去。if (children children.length 0) {this.getShowData(children)}})} 修改数据 // 获取新的treeData数据removeShowData (datas) {const { selectedKeys } this.stateconst newData datas;function setGrayNode(data){ //遍历树 获取id数组for(var i0;idata.length;i){if(data[i].key selectedKeys[0]){// 如果某一个节点是禁用的它的所有子节点都应该禁用delete data[i].childrencontinue;} else {if(data[i].children){// 如果当前节点有子节点就递归调用一次setGrayNode(data[i].children);}}}}setGrayNode(newData)return newData;} 七、总结 一个星期下来还是比较累的原因是因为组件使用不熟练且自己的技术力较弱导致的但好在也顺利完成任务倒也没有什么大碍。记录一下这一个星期以来遇到的一些问题和实践吧。前端小白一枚如有错误欢迎指正。 源码 import React, { Component } from react; import { connect } from dva; import {Modal,Button,Tree,Row,Col,Empty,Tooltip,Icon,Upload,Popconfirm,Select,Spin,notification } from antd; import { formatMessage, FormattedMessage } from umi-plugin-locale; import globalUtil from ../../utils/global import download from /utils/download; import apiconfig from ../../../config/api.config; import SVG from ./svg; import styles from ./index.less;const { TreeNode, DirectoryTree } Tree; connect(({ appControl }) ({appDetail: appControl.appDetail,}) )class Index extends Component {constructor(props) {super(props);this.state {treeData: [],selectedKeys: [],expandedKeys: [],pathArr: [],keyArr: [],dowloadArr: [],path: ,podsList: [],selectDefaultValue: ,hostPath: this.props this.props.hostPath,selectLoading: false,treeDataLoading: false,loadedKeys:[]}}componentDidMount() {this.fetchInstanceInfo()}// 获取podnamefetchInstanceInfo () {const { dispatch } this.props;dispatch({type: appControl/fetchPods,payload: {team_name: globalUtil.getCurrTeamName(),app_alias: this.props.appAlias,},callback: res {if (res res.list) {this.setState({podsList: res.list.new_pods,selectDefaultValue: res res.list res.list.new_pods[0] res.list.new_pods[0].pod_name,selectLoading: true}, () {if (this.props.isType) {this.determineStorageType()}else{this.getListFiles()}})}}});};// 获取文件类型determineStorageType () {this.props.dispatch({type: appControl/determineStorageType,payload: {team_name: globalUtil.getCurrTeamName(),group_id: this.props.appAlias,region_name: globalUtil.getCurrRegionName(),pod_name: this.state.selectDefaultValue,namespace: this.props.appDetail this.props.appDetail.service this.props.appDetail.service.namespace,volume_path: this.props his.props.volumePath,},callback: res {if(res){this.setState({hostPath: res.bean,},(){this.getListFiles()})}}});};// 获取文件列表getListFiles () {this.props.dispatch({type: appControl/getListFiles,payload: {team_name: globalUtil.getCurrTeamName(),group_id: this.props.appAlias,region_name: globalUtil.getCurrRegionName(),pod_name: this.state.selectDefaultValue,host_path: this.props.appDetail this.props.appDetail.service this.props.appDetail.service.extend_method state_multiple ? ${this.state.hostPath}/${this.state.selectDefaultValue} : this.state.hostPath,extend_method: this.props.appDetail this.props.appDetail.service this.props.appDetail.service.extend_method},callback: res {if (res res.list) {res.list.map((item, index) {item.key index,item.isLeaf item.is_leaf})this.setState({treeData: res.list,showData: res.list,treeDataLoading: true})}},handleError: res {if(res){notification.error({ message: formatMessage({id:componentOverview.body.DirectoryPersistence.error}) });this.setState({showData: [],treeData: []})}}});}// 获取文件列表updataListFiles (path) {this.setState({treeDataLoading: false},(){this.props.dispatch({type: appControl/getListFiles,payload: {team_name: globalUtil.getCurrTeamName(),group_id: this.props.appAlias,region_name: globalUtil.getCurrRegionName(),pod_name: this.state.selectDefaultValue,host_path: this.props.appDetail this.props.appDetail.service this.props.appDetail.service.extend_method state_multiple ? ${this.state.hostPath}/${this.state.selectDefaultValue}${path} : ${this.state.hostPath}${path},extend_method: this.props.appDetail this.props.appDetail.service this.props.appDetail.service.extend_method},callback: res {if (res res.list) {res.list.map((item, index) {item.key index,item.isLeaf item.is_leaf})this.setState({treeData: res.list,showData: res.list,treeDataLoading: true})}},handleError: res {if(res){notification.error({ message: formatMessage({id:componentOverview.body.DirectoryPersistence.error}) });this.setState({showData: [],treeData: []})}}});})}// 加载树图onLoadData treeNode new Promise(resolve {if (treeNode.props.children) {resolve();return;}setTimeout(() {this.props.dispatch({type: appControl/getListFiles,payload: {team_name: globalUtil.getCurrTeamName(),group_id: this.props.appAlias,region_name: globalUtil.getCurrRegionName(),pod_name: this.state.selectDefaultValue,host_path: this.props.appDetail this.props.appDetail.service this.props.appDetail.service.extend_method state_multiple ? ${this.state.hostPath}/${this.state.selectDefaultValue}/${this.state.path} : ${this.state.hostPath}/${this.state.path},extend_method: this.props.appDetail this.props.appDetail.service this.props.appDetail.service.extend_method},callback: res {if (res) {if (res.list res.list.length 0) {this.setState({treeData: [...this.state.treeData],showData: res.list});treeNode.props.dataRef.children []resolve();} else {const arr res.listarr.map((item, index) {item.key ${treeNode.props.eventKey}-${index}item.isLeaf item.is_leaf})treeNode.props.dataRef.children arrthis.setState({treeData: [...this.state.treeData],showData: res.list});resolve();}}}});}, 100)});// 渲染函数renderTreeNodes data data data.map((item, index) {if (item.isLeaf) {return (TreeNode title{item.title} key{item.key} dataRef{item} {this.renderTreeNodes(item.children)}/TreeNode);}return null;});//选择树节点 onSelect (selectedKeys, info) {// 选择为空时直接returnif (selectedKeys selectedKeys.length 0) {return null}if (info) {const { selectedNodes } infoconst { props } selectedNodes[0]const { dataRef } propsthis.setState({selectedKeys: selectedKeys,expandedKeys: this.state.expandedKeys.includes(selectedKeys[0]) ? [...this.state.expandedKeys] : [...this.state.expandedKeys, ...selectedKeys],showData: dataRef.children || this.state.showData,dowloadArr: [],pathArr: [],path: }, () {this.getPath()})} else {this.setState({selectedKeys: selectedKeys,expandedKeys: this.state.expandedKeys.includes(selectedKeys[0]) ? [...this.state.expandedKeys] : [...this.state.expandedKeys, ...selectedKeys],dowloadArr: [],pathArr: [],path: }, () {this.getPath()})}}onLoad (loadedKeys) {this.setState({loadedKeys: loadedKeys})}// 展开树图onExpand (expandedKeys, info) {let newLoadKeys this.state.loadedKeysif (this.state.expandedKeys.length expandedKeys.length) {// 当是收起的时候把这个收起的节点从loadedKeys中移除newLoadKeys this.state.loadedKeys.filter((i) expandedKeys.includes(i))}this.setState({expandedKeys: expandedKeys,selectedKeys: [${info.node.props.dataRef.key}],showData: info.node.props.dataRef.children,loadedKeys: newLoadKeys}, () {this.getPath()})};// 获取后缀名getSvgIcon (name) {if (name) {const str name.substr(name.lastIndexOf(.) 1)return ${str}}}// 鼠标点击folderClick (data) {// 判断data数据是否有孩子如果没有就加载如果有就if (data data.children data.children.length 0) {this.setState({expandedKeys: [...this.state.expandedKeys, ...[${data.key}]],selectedKeys: [${data.key}],showData: data.children,dowloadArr: []}, () {this.getPath()})} else {this.setState({expandedKeys: [...this.state.expandedKeys, ...[${data.key}]],selectedKeys: [${data.key}],dowloadArr: []}, () {this.getPath()})}}//递归获取Showdata数据 getShowData (datas) {const { selectedKeys } this.statedatas.map(item {const { key, children } itemif (key selectedKeys[0]) {this.setState({showData: datas})}if (children children.length 0) {this.getShowData(children)}})}// 获取key值的path数据getPathData (data) {const { treeData, keyArr } this.statedata.map(item {const { title, children } itemif (keyArr.indexOf(${item.key}) ! -1) {const arr this.state.pathArrarr.push(title)this.setState({pathArr: arr})}if (children children.length 0) {this.getPathData(children)}})}//递归获取path数据 getPath () {const { selectedKeys, treeData, pathArr } this.stateif (selectedKeys []) {return}if (selectedKeys selectedKeys[0]) {const length selectedKeys[0].lengthconst str selectedKeys[0]const arr str.split(-)const keyArr []for (let index 0; index arr.length 1; index) {const newarr arr.slice(0, index)const newstr newarr.join(-)keyArr.push(newstr)}keyArr.shift();this.setState({keyArr: keyArr,pathArr: []}, () {this.getPathData(treeData)})setTimeout(() {const path this.state.pathArr.join(/)this.setState({path: path})}, 100)}}// 返回上一级goBack () {const { selectedKeys } this.state// 如果选择为空则展示所有数据if (selectedKeys[0] undefined) {return}// 如果选择有值且值不大于1if ((selectedKeys[0]).indexOf(-) -1) {this.setState({selectedKeys: [],showData: this.state.treeData,dowloadArr: []}, () {this.getPath()})// 如果选择有值且值大于1} else {this.getShowData(this.state.treeData)this.setState({selectedKeys: [${selectedKeys[0].substring(0, (selectedKeys[0]).lastIndexOf(-))}],dowloadArr: []}, () {this.getPath()})}}// 下载dowloadTitle (val) {const { dowloadArr } this.statesetTimeout(() {if (dowloadArr.includes(val)) {const arr []dowloadArr.map(item {if (item ! val) {arr.push(item)}})this.setState({dowloadArr: [...arr]})} else {const arr []arr.push(val)this.setState({dowloadArr: [...this.state.dowloadArr, ...arr]})}}, 10)}// 下拉框选择selectChange (val) {this.setState({selectDefaultValue: val},(){this.getListFiles()})}fileDownload () {const { dowloadArr } this.stateif(dowloadArr.length 0 ){notification.info({ message: formatMessage({id:componentOverview.body.DirectoryPersistence.download}) });}else{dowloadArr.map(item {this.fileDownloadApi(item)})}setTimeout((){this.setState({dowloadArr:[]})},100)}// 下载接口fileDownloadApi ( title ) {const dowloadPath this.state.path ? this.props.appDetail this.props.appDetail.service this.props.appDetail.service.extend_method state_multiple ? ${this.state.hostPath}/${this.state.selectDefaultValue}/${this.state.path} : ${this.state.hostPath}/${this.state.path} : this.props.appDetail this.props.appDetail.service this.props.appDetail.service.extend_method state_multiple ? ${this.state.hostPath}/${this.state.selectDefaultValue} : ${this.state.hostPath};const host apiconfig.baseUrl;const url host.slice(0,host.lastIndexOf(:))// const path ${url}:6060/v2/ws/download/${title}?path${dowloadPath}const path http://47.104.161.96:6060/v2/ws/download/${title}?path${dowloadPath}this.download(${path},title)}download (downloadPath, title) {console.log(title.indexOf(txt) -1,title.indexOf() -1);if(title.indexOf(txt) -1){let aEle document.querySelector(#down-a-element);if (!aEle) {aEle document.createElement(a);aEle.setAttribute(target, _blank)aEle.setAttribute(download, title);document.body.appendChild(aEle);}aEle.href downloadPath;if (document.all) {aEle.click();} else {const e document.createEvent(MouseEvents);e.initEvent(click, true, true);aEle.dispatchEvent(e);}}else{var element document.createElement(a);element.setAttribute(href, data:text/plain;charsetutf-8, encodeURIComponent(title));element.setAttribute(download, title);element.style.display none;document.body.appendChild(element);element.click();document.body.removeChild(element);}};uploadChange info {const { path, selectedKeys } this.stateif (info info.file info.file.status done) {notification.success({ message: formatMessage({id:notification.success.upload})});if(selectedKeys[0] undefined){this.getListFiles()}else{this.updateTree()}} else if (info info.file info.file.status error) {notification.error({ message: formatMessage({id:notification.error.update}) });}};updateTree () {const { selectedKeys , expandedKeys, loadedKeys, treeData } this.state// 获取新的expandedKeys数组不包含该节点及子节点const newExpandedKeys expandedKeys.filter(item {return item.indexOf(selectedKeys[0]) -1})// 获取新的loadedKeys数组不包含该节点及子节点const newLoadedKeys loadedKeys.filter(item {return item.indexOf(selectedKeys[0]) -1})const newTreedata treeDatathis.setState({expandedKeys: [...newExpandedKeys,...[${selectedKeys[0]}]],loadedKeys: [...newLoadedKeys],treeData: this.removeShowData(newTreedata),selectedKeys: [${selectedKeys[0]}],})}// 获取新的treeData数据removeShowData (datas) {const { selectedKeys } this.stateconst newData datas;function setGrayNode(data){ //遍历树 获取id数组for(var i0;idata.length;i){if(data[i].key selectedKeys[0]){// 如果某一个节点是禁用的它的所有子节点都应该禁用delete data[i].childrencontinue;} else {if(data[i].children){// 如果当前节点有子节点就递归调用一次setGrayNode(data[i].children);}}}}setGrayNode(newData)return newData;}render() {const {selectedKeys,expandedKeys,showData,path,dowloadArr,podsList,selectDefaultValue,selectLoading,treeDataLoading,hostPath,loadedKeys} this.stateconst upLoadPath this.state.path ? this.props.appDetail this.props.appDetail.service this.props.appDetail.service.extend_method state_multiple ? ${this.state.hostPath}/${this.state.selectDefaultValue}/${this.state.path} : ${this.state.hostPath}/${this.state.path} : this.props.appDetail this.props.appDetail.service this.props.appDetail.service.extend_method state_multiple ? ${this.state.hostPath}/${this.state.selectDefaultValue} : ${this.state.hostPath};const host apiconfig.baseUrl;const url host.slice(0,host.lastIndexOf(:))// const upload ${url}:6060/v2/ws/uploadconst upload http://47.104.161.96:6060/v2/ws/uploadconst props {action: upload,data:{path: upLoadPath},method:post,name:packageTarFile,};const isFile showData.filter(item { return item.title.indexOf(.) -1 })const notFile showData.filter(item { return item.title.indexOf(.) ! -1 })const folder []isFile.map((item,index) {if(item.isLeaf true){folder.unshift(item)}else{folder.push(item)}})const showDataArr [...folder,...notFile]return (divModalclassName{styles.ModalStyle}title{{formatMessage({id:componentOverview.body.DirectoryPersistence.example})}Selectvalue{selectDefaultValue}style{{ maxWidth: 184, marginLeft: 5 }}onChange{this.selectChange}loading{!selectLoading}{podsList podsList.length 0 podsList.map(item {return Select.Option value{item.pod_name}{item.pod_name}/Select.Option})}/Select/}visible{true}width{1000}closable{false}footer{Upload{...props}showUploadList{false}multipleonChange{this.uploadChange}// directory{true}Button typeprimary style{{ marginRight: 10 }}Icon typeupload / {formatMessage({id:applicationMarket.Offline.upload})}/Button/UploadButton typeprimary onClick{this.fileDownload}Icon typedownload /{formatMessage({id:button.download})}/ButtonButton onClick{this.props.isShow}{formatMessage({id:popover.cancel})}/Button/}{treeDataLoading ? (RowCol span{6}TreeloadData{this.onLoadData}onSelect{this.onSelect}selectedKeys{selectedKeys}onExpand{this.onExpand}expandedKeys{expandedKeys}switcherIcon{Icon typedown /}onLoad{this.onLoad} loadedKeys{loadedKeys} {this.renderTreeNodes(this.state.treeData)}/Tree/ColCol span{18} style{{ position: relative }}div className{styles.goBack}button onClick{this.goBack}{SVG.getSvg(goBack, 12)}{formatMessage({id:componentOverview.body.DirectoryPersistence.return})}/button/divdiv className{styles.iconShow}{showDataArr showDataArr.length 0 ? (showDataArr.map((item, index) {const { title, isLeaf } itemif (isLeaf) {return div className{styles.outerLayer} style{{ cursor: pointer }} onDoubleClick{() this.folderClick(item)}div{SVG.getSvg(file, 70)}/divdivTooltip placementtop title{item.title}{item.title}/Tooltip/div/div} else {return div className{styles.outerLayer} onClick{() this.dowloadTitle(item.title)} style{{ background: dowloadArr.includes(item.title) ? #e6f7ff : #fff }}div{SVG.getSvg(this.getSvgIcon(title), 70)}/divdivTooltip placementtop title{item.title}{item.title}/Tooltip/div/div}})) : (Empty className{styles.emptyStyle} /)}/div/Col/Row) : (Spin sizelarge style{{width: 100%,height: 400,display: flex,alignItems: center,justifyContent: center,}} /)}/Modal/div);} }export default Index;
http://www.hkea.cn/news/14562363/

相关文章:

  • 黄岐建网站温岭新站seo
  • 企业类网站包括哪些360浏览器屏蔽某网站怎么做
  • 前几年做哪个网站能致富制作app软件要多少钱一个
  • 济南做网站哪里好北京移动端网站多少钱
  • 贵阳网站制作工具漳州网站建设网站运营
  • 唐山网站制作网络公司黑帽seo软件
  • 建设网站企业无锡市滨湖区建设局网站
  • 跨境电商网站开发技术学校网站建设工作计划
  • 全屏的翻页网站这么做o2o网站建设方案ppt
  • wordpress移动端视频做seo网站标题用什么符号
  • 佛山企业网站建设服务濮阳做网站公司
  • 网站备案初审过了理财网站开发
  • 如何填写网站开发验收单外贸网站搭建服务商
  • 网站建设哪个公司的好简单网站建设报价单
  • 如何写网站建设策划案网站建设中请期待
  • 做网站加一个定位功能要多少钱翻译建设企业网站
  • 广州网站建设设计哪家好如何搭建一个网站步骤
  • 建站 discuz广告门网站
  • 怎么查询网站开通时间网站建设课程中的收获
  • 企业为何要做网站安徽省建设厅网站职称申报
  • 梅州建站网络有限公司中国中建设计集团有限公司
  • 给别人做网站挣钱么网站案例分析
  • asp网上书店网站开发网站建设怎么做更好
  • 沈阳网站推广优化排名公司成都百度推广公司联系电话
  • 建设环保网站的目的与功能分析中国十大影视公司排名
  • 网站建设项目验收报告书杭州专业网站优化公司
  • 网站开发视频下载游戏平台搭建
  • 公司网站建设应注意哪些企业宣传片制作app
  • 在阿里巴巴做网站多少钱2019线上商城app
  • 如何做登陆界面的网站免费html网站代码