您现在的位置是:首页 > 技术教程 正文

记录-若依前端集成markdown文档,自动生成文档目录

admin 阅读: 2024-04-01
后台-插件-广告管理-内容页头部广告(手机)

使用版本: vue 2.6.12 html-loader 1.3.2 markdown-loader 6.0.0 github-markdown-css ^5.5.1 highlight.js 9.18.5 webpack @4.47.x

一.引入loder插件,html-loader和markdown-loader
//安装 pnpm install html-loader --save ; pnpm install markdown-loader --save;
  • 1
  • 2
  • 3

在vue.config文件中配置webpack配置,主要代码:

// html-loader markdown-loader config.module .rule('md') //.test(/\.md/) .test(/\.md$/) .use('html-loader') .loader('html-loader') .end() .use('markdown-loader') .loader('markdown-loader') .end()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在安装插件时,需注意插件对应的webpack版本,与你项目的webpack版本是否支持,不支持则会报以下错误:
在这里插入图片描述
解决办法:在GitHub上搜插件源码,查找历史版本,卸载原来的插件 pnpm uninstall html-loader,重装历史固定版本来适配webpack版本,安装固定版本: pnpm install html-loader@版本号

二.在页面中使用
<template> <div class="app-container1"> <div class="wrap"> <div v-if="isMarkDown"> <div v-highlight id="content" class="markdown-body" v-html="markdownContent">div> <div class="api-tree" id="tree"> <el-tree highlight-current :expand-on-click-node="false" :data="tree" :default-expand-all="true" @node-click="handleNodeClick" >el-tree> div> div> <vue-office-pdf v-if="!isMarkDown" :src="src" @rendered="renderedHandler" @error="errorHandler" /> div> div> template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

注意:markdown文档容器样式class必须加上’markdown-body’class=“markdown-body” 否则无法识别

三.引用markdown默认样式
// 安装 pnpm install github-markdown-css --save
  • 1
  • 2

在页面中引用:
import “github-markdown-css”;

四.引用代码高亮样式_highlight.js
// 安装 pnpm install highlight.js --save
  • 1
  • 2

在min.js 中进行全局注册,注册成指令:
min.js:

import hljs from "highlight.js"; Vue.prototype.$hljs = hljs; // 有多种样式可选,也可以到对应文件中定制化 import "highlight.js/styles/vs.css"; // 自定义命令v-highlight Vue.directive("highlight", function(el) { let blocks = el.querySelectorAll("pre code"); blocks.forEach(block => { hljs.highlightBlock(block); }); });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

import “highlight.js/styles/vs.css”;
这里引入的样式选择可到官网去查看样式效果:
highlight_Demo
在页面中使用方法:
在Dom元素中加上v-highlight

<div v-highlight id="content" class="markdown-body" v-html="markdownContent">div>
  • 1
五.自动生成markdown文档目录

现在,我们需要有目录大纲方便我们查看文档。我的思路是,首先拿到markdown文件的html结构,然后找到所有H1-H5的标题标签,并给这些标签设置id,生成一个新数组,通过这个数组生成目录结构

//html部分 <div class="api-tree" id="tree"> <el-tree :data="tree" :default-expand-all="true" @node-click="handleNodeClick" ></el-tree> </div> // js部分 catalogTree() { const content = document.getElementById("content").children; var arr = []; let currentHightestLevel; let parentId; let index = 0; for (let i = 0; i < content.length; i++) { let header = content[i].localName; if (/\b[h][0-9]\b/.test(header)) { let ele = $(content[i]); let name = ele.text(); // 设置id ele.attr("id", i); let id = i; if (index === 0 || header <= currentHightestLevel) { currentHightestLevel = header; parentId = id; } arr.push({ id: id, label: name, parentId: parentId == id ? "0" : parentId, }); index++; } } const tree = []; arr.forEach((item) => { if (item.parentId === "0") { tree.push(this.convertArrayToTree(arr, item)); } }); this.tree = tree; }, convertArrayToTree(arr, node) { for (let i = 0; i < arr.length; i++) { if (arr[i].parentId === node.id) { const res = this.convertArrayToTree(arr, arr[i]); if (node.children) { node.children.push(res); } else { node.children = [res]; } } } return node; }, handleNodeClick(data) { let anchorElement = document.getElementById(data.id); if (anchorElement) { anchorElement.scrollIntoView({ behavior: "smooth", block: "end", }); } },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

这里出现了一个问题,那就是要给父容器一个滚动条,否则点击目录无法自动移动到对应位置,我是在App.vue里面设置了一个样式叫article-list ,其中设置了父容器的滚动条为自适应,id设置为app

.article-list { overflow-y: auto; }
  • 1
  • 2
  • 3
<template> <div id="app" class="article-list"> <router-view /> <theme-picker /> </div> </template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后修改handleNodeClick方法:

handleNodeClick(data) { let anchorElement = document.getElementById(data.id); let scrollPosition = anchorElement.offsetTop-88; this.$nextTick(()=>{ let myElement = document.getElementById("app"); myElement.scrollTo({ left: 0, top: scrollPosition, behavior: "smooth", }) }); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
六.卡片样式,想要一个像element ui 一样的卡片样式,找到其卡片组件,复制对应的样式到对应的div块上应用即可

部分源码以及效果图:

<template> <div class="app-container1"> <el-button style="margin:8px 9px 8px 11px;" type="primary" size="mini" @click="showUpload" v-hasPermi="['system:wiki:upload']">上传<i class="el-icon-upload el-icon--right"></i></el-button> <el-row style="display: flex;justify-content: center;margin-bottom:8px;"> <el-col :span="24"> <el-card class="box-card" style="width:98%;margin-left: 10px;"> <div slot="header" class="clearfix"> <span>ems资料</span> </div> <div v-for="(fileName, index) in fileList" :key="index" class="text item"> <div :id="'file_' + index" style="display:inline-block;"> {{ fileName }} </div> <!-- 下载按钮 --> <div style="float: right;display: flex;justify-content: space-between;" :style="{width:fileName.indexOf('.md') === -1?'155px':'103px',marginRight:fileName.indexOf('.md') === -1?'0':'53px'}"> <el-link type="primary" size="mini" icon="el-icon-view" @click="viewFile(fileName, index)">预览</el-link> <el-link type="primary" v-if="fileName.indexOf('.md')===-1" size="mini" icon="el-icon-download" @click="download(fileName)" v-hasPermi="['system:wiki:downFile']">下载</el-link> <!-- 删除 --> <el-link type="danger" v-if="fileName.indexOf('.md')===-1" size="mini" icon="el-icon-delete" @click="clickdeleteFile(fileName)" v-hasPermi="['system:wiki:delete']">删除</el-link> </div> </div> </el-card> </el-col> </el-row> <div class="wrap"> <div v-if="isMarkDown"> <div v-highlight id="content" class="markdown-body" v-html="markdownContent"></div> <div class="api-tree" id="tree"> <el-tree highlight-current :expand-on-click-node="false" :data="tree" :default-expand-all="true" @node-click="handleNodeClick" ></el-tree> </div> </div> <vue-office-pdf v-if="!isMarkDown" :src="src" @rendered="renderedHandler" @error="errorHandler" /> </div> <el-dialog title="提示" :visible.sync="uploadVisible" width="30%"> <el-upload class="upload-demo" drag action="#" accept=".pdf" multiple :headers="headers" :auto-upload="false" :file-list="uploadfileList" :on-change="handleChange"> <i class="el-icon-upload"></i> <div class="el-upload__text">将pdf文件拖到此处,或<em>点击上传</em></div> </el-upload> <span slot="footer" class="dialog-footer"> <el-button @click="uploadVisible = false">取 消</el-button> <el-button type="primary" @click="confirmUpload">确 定</el-button> </span> </el-dialog> </div> </template> <script> import VueOfficePdf from '@vue-office/pdf' // markdown样式 import "github-markdown-css"; // markDown默认样式 import $ from "jquery"; import { getFile, uploads, getFileName, downFile, deleteFile } from '@/api/ems/common'; export default { components: { VueOfficePdf }, data() { return { headers: { 'Content-Type': 'multipart/form-data' }, uploadfileList: [], fileList: [], // 文件列表数据 src: '', uploadVisible: false, // 控制上传组件的显示状态 curreSelectFileIndex: -1, markdownContent: '', key: 0, tree: [], isMarkDown: false, }; }, watch: { }, methods: { clickdeleteFile(fileName) { console.log(fileName + '删除文件') //把fileName类如test - 副本 (2).pdf查看文件转为string fileName = fileName.toString() deleteFile(fileName).then(response => { console.log(response); this.$message({ message: '删除成功', type: 'success' }); this.loadFileList(); }) }, handleChange(file, fileList) { //文件数量改变 console.log(fileList) //判断file类型如果不是pdf格式,提示用户,并且将fileList中的file删除 fileList.forEach((item, index) => { if (item.name.indexOf('.pdf') == -1) { this.$message.error('文件格式不正确,请上传pdf格式文件'); fileList.splice(index, 1); } }) this.uploadfileList = fileList; }, confirmUpload() { var formData = new FormData(); this.uploadfileList.forEach(file => { formData.append('files', file.raw); }); uploads(formData).then(response => { console.log(response); this.$message({ message: '上传成功', type: 'success' }); }).catch(error => { console.error('上传失败:', error); this.$message.error('上传失败'); }); setTimeout(() => { this.loadFileList(); }, 1000); // 延迟时间,单位为毫秒 this.uploadfileList = []; this.uploadVisible = false; }, uploadFile(event) { console.log('上传文件'); const files = event.target.files; console.log(files); uploads(files).then(response => { console.log(response); }) }, loadFileList() { const context = require.context('@/assets/document', false, /\.md/); // 查找pdf或md /[\.pdf$][\.md$]/ const modulePaths = context.keys(); //遍历modulePaths去掉路径前缀'./'然后赋值给fileList this.fileList = modulePaths.map(item => item.replace('./', '')); getFileName().then(response => { console.log(response.data + '文件列表'); response.data.forEach(x=>{ this.fileList.push(x); }) }) }, showUpload() { this.uploadVisible = true }, renderedHandler() { console.log("渲染完成") }, errorHandler() { console.log("渲染失败") }, viewFile(fileName, index) { const loading = this.$loading({ lock: true, text: 'Loading', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }); this.changeLineColor(index); // 收起菜单 // hamburger-container if(this.$store.getters.sidebar.opened === true) { this.$store.dispatch('app/toggleSideBar'); } console.log(fileName + '查看文件') //把fileName类如test - 副本 (2).pdf查看文件转为string fileName = fileName.toString() if(fileName.endsWith('.md')) { this.isMarkDown=true; this.loadMd(fileName); setTimeout(() => { loading.close(); }, 300); return; } this.isMarkDown=false; //调用后台接口,获取文件地址 getFile(fileName).then(response => { const byteArray = atob(response.data); const uint8Array = new Uint8Array(byteArray.length); for (let i = 0; i < byteArray.length; i++) { uint8Array[i] = byteArray.charCodeAt(i); } const blob = new Blob([uint8Array]); let fileBytes = response.data; let fileReader = new FileReader(); fileReader.readAsArrayBuffer(blob); fileReader.onload = () => { this.src = fileReader.result } setTimeout(() => { loading.close(); }, 300); }) }, changeLineColor(index) { let current = document.getElementById('file_' + this.curreSelectFileIndex); if (current != null) { current.className = ''; } this.curreSelectFileIndex = index; let ele = document.getElementById('file_' + index); ele.className = "viewLine"; }, download(fileName) { console.log(fileName + '下载文件') //把fileName类如test - 副本 (2).pdf查看文件转为string fileName = fileName.toString() downFile(fileName).then(response => { const byteArray = atob(response.data); const uint8Array = new Uint8Array(byteArray.length); for (let i = 0; i < byteArray.length; i++) { uint8Array[i] = byteArray.charCodeAt(i); } const blob = new Blob([uint8Array]); // 创建 URL 对象 const url = URL.createObjectURL(blob); // 创建 元素 const link = document.createElement('a'); link.href = url; link.download = fileName; // 设置下载文件的名称 link.click(); // 释放 URL 对象 URL.revokeObjectURL(url); }) }, catalogTree() { const content = document.getElementById("content").children; var arr = []; let currentHightestLevel; let parentId; let index = 0; for (let i = 0; i < content.length; i++) { let header = content[i].localName; if (/\b[h][0-9]\b/.test(header)) { let ele = $(content[i]); let name = ele.text(); // 设置id ele.attr("id", i); // let id = ele.children("a").attr("id"); let id = i; if (index === 0 || header <= currentHightestLevel) { currentHightestLevel = header; parentId = id; } arr.push({ id: id, label: name, parentId: parentId == id ? "0" : parentId, }); index++; } } const tree = []; arr.forEach((item) => { if (item.parentId === "0") { tree.push(this.convertArrayToTree(arr, item)); } }); this.tree = tree; }, convertArrayToTree(arr, node) { for (let i = 0; i < arr.length; i++) { if (arr[i].parentId === node.id) { const res = this.convertArrayToTree(arr, arr[i]); if (node.children) { node.children.push(res); } else { node.children = [res]; } } } return node; }, handleNodeClick(data) { let anchorElement = document.getElementById(data.id); let scrollPosition = anchorElement.offsetTop-88; this.$nextTick(()=>{ let myElement = document.getElementById("app"); myElement.scrollTo({ left: 0, top: scrollPosition, behavior: "smooth", }) }); }, loadMd(fileName) { const conTxt = require(`@/assets/document/${fileName}`); if(conTxt) { this.markdownContent = conTxt; this.$nextTick(() => { this.catalogTree(); }); } this.key += 1; } }, mounted() { console.log('mounted'); this.loadFileList(); } }; </script> <style scoped lang="scss"> .text { font-size: 14px; font-weight: bold; } .item { margin-bottom: 16px; } .clearfix:before, .clearfix:after { display: table; content: ""; } .clearfix:after { clear: both } ::v-deep .el-card__body { padding: 15px 15px 10px 13px; } .viewLine { color: rgb(54, 152, 126); } // 修改第三方组件样式 + ::v-deep 和 !important 和 父容器 wrap .wrap ::v-deep .vue-office-pdf .vue-office-pdf-wrapper { padding: 10px 10px !important; background: rgb(44, 30, 71, 0.86) !important; } // 修改第三方组件样式 + ::v-deep 和 !important 和 父容器 wrap .wrap ::v-deep .vue-office-pdf .vue-office-pdf-wrapper canvas { width: 100% !important; border-radius: 4px !important; } .markdown-body { display: inline-block; //float: right; min-width: 200px; max-width: 83%; margin-left: 10px; font-size: 18px; // 卡片样式部分 box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); border-radius: 4px; border: 1px solid #e6ebf5; background-color: #FFFFFF; overflow: hidden; color: #303133; -webkit-transition: 0.3s; transition: 0.3s; // 卡片样式结束 padding-left: 20px; padding-right: 15px; padding-top: 40px; padding-bottom: 25px; margin-right: 25px; margin-bottom: 30px; h2 { font-size: 18px; margin: 1em 0 15px; padding-top: 0.8em; padding-bottom: 0.8em; } h3 { font-size: 14px; margin: 22px 0 16px; } h4 { font-size: 13px; margin: 20px 0 16px; } h5 { font-size: 12px; margin: 16px 0 16px; font-weight: 700; } p { font-size: 12px; line-height: 24px; color: #666666; margin-top: 0px; margin: 8px 0; margin: 14px 0 14px; } pre { background-color: #eee; margin-bottom: 8px; margin-top: 8px; margin: 12px 0 12px; } blockquote { margin-bottom: 8px; margin-top: 8px; margin: 14px 0 14px; background-color: #eee; padding: 16px 16px; } tr { background-color: #f5f5f5; } code { background-color: #eee; } ul, ol, li { list-style: unset; font-size: 12px; line-height: 20px; color: #666666; margin-top: 0px; margin: 8px 0; } blockquote { border-color: #48b6e2; } table { display: table; width: 100%; max-width: 100%; margin-bottom: 20px; } } .api-tree { padding-left: 7px; display: inline-block; position: fixed; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); border-radius: 4px; border: 1px solid #e6ebf5; background-color: #FFFFFF; overflow: hidden; color: #303133; -webkit-transition: 0.3s; transition: 0.3s; top: 56%; right: 2%; transform: translate(2%, 20%); width: 200px; height: 265px; // 265px overflow-y: auto; font-weight: bold; //z-index: 99; .el-tree { background: none; color: rebeccapurple; /* 改变被点击节点背景颜色,字体颜色 */ } } ::v-deep .el-tree-node:focus > .el-tree-node__content, .el-tree-node__content:hover { background: rgb(0, 125, 12,0.4) ; color: rgb(255, 24, 93,0.6); } ::v-deep .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content{ background: rgb(0, 125, 12,0.4) ; color: rgb(255, 24, 93,0.6); } ::v-deep .el-tree-node__expand-icon{ display: none; } </style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496

图1-显示markdown文档,自动生成目录:
在这里插入图片描述
图2-代码高亮
在这里插入图片描述

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索