-
-
-
{{item.type}}
+
+
+
+
{{item.type}}
+
+
+
+
+ 导入/导出:
+
+
+
+
@@ -69,6 +79,7 @@ import { watch } from '@vue/runtime-core'
import Dialog from './components/Dialog.vue'
import gsap from 'gsap'
import { ElMessage } from 'element-plus'
+import { importBookmark, exportBookmark } from './components/utils.js'
var rowData = []
function getData(fn = () => {}) {
// 数据持久化
@@ -126,11 +137,17 @@ export default {
// 新增书签
function add(row = {}, flag = 'add') {
- const temp = {...row}
+ const temp = { ...row }
if (flag === 'modify') {
- data.detail = Object.assign(temp, { type: rowData[data.activeIndex].type, flag: 'modify' })
+ data.detail = Object.assign(temp, {
+ type: rowData[data.activeIndex].type,
+ flag: 'modify'
+ })
} else {
- data.detail = Object.assign({}, { type: rowData[data.activeIndex].type, flag: 'add' })
+ data.detail = Object.assign(
+ {},
+ { type: rowData[data.activeIndex].type, flag: 'add' }
+ )
}
data.isDetailVisible = true
}
@@ -147,10 +164,14 @@ export default {
// 删除
const deleteClick = (row) => {
const myData = JSON.parse(localStorage.getItem('BOOKMARK'))
- const delDetail = Object.assign(row, { type: rowData[data.activeIndex].type })
+ const delDetail = Object.assign(row, {
+ type: rowData[data.activeIndex].type
+ })
for (let i = 0; i < myData.length; i++) {
if (delDetail.type === myData[i].type) {
- const cindex = myData[i].children.findIndex(s => s.title === delDetail.title)
+ const cindex = myData[i].children.findIndex(
+ (s) => s.title === delDetail.title
+ )
if (cindex > -1) {
myData[i].children.splice(cindex, 1)
localStorage.setItem('BOOKMARK', JSON.stringify(myData))
@@ -167,7 +188,9 @@ export default {
navigate,
add,
closeViews,
- search
+ search,
+ importBookmark,
+ exportBookmark
}
},
methods: {
@@ -218,7 +241,7 @@ export default {
border: 1px solid rgba(255, 255, 255, 0.18);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
position: relative;
- overflow-y: auto;
+ // overflow-y: auto;
padding: 8px 0;
img {
width: 20px;
@@ -283,7 +306,7 @@ export default {
animation: 0.3ms;
box-shadow: 0 8px 18px 0 rgba(31, 38, 135, 0.3);
}
- &:hover .logo-box-tools{
+ &:hover .logo-box-tools {
opacity: 0.85;
}
}
@@ -444,7 +467,7 @@ export default {
right: 0;
top: 0;
opacity: 0;
- transition:0.4s opacity;
+ transition: 0.4s opacity;
i {
padding: 4px;
display: inline-block;
@@ -455,4 +478,52 @@ export default {
}
}
}
+
+.import-tool {
+ position: absolute;
+ width: 100%;
+ background: #fbf5f5;
+ height: 36px;
+ padding: 3px 15px;
+ display: flex;
+ align-items: center;
+ bottom: 0;
+ z-index: 99;
+ i {
+ font-size: 18px;
+ margin: 1px 4px;
+ padding: 4px;
+ cursor: pointer;
+ color: #e03b5d;
+ background: #ff00001f;
+ border-radius: 5px;
+ opacity: 0.7;
+ &:hover {
+ color: #e03b5d;
+ background: #c804041f;
+ opacity: 1;
+ }
+ }
+}
+.left-box-item {
+ height: 100%;
+ overflow-y: auto;
+ padding-bottom: 40px;
+}
+.import-text {
+ font-size: 12px;
+ color: #999;
+ margin-right: 3px;
+}
+.el-icon-upload2 {
+ position: relative;
+ input {
+ width: 1.46rem;
+ height: 100%;
+ z-index: 1;
+ opacity: 0;
+ position: absolute;
+ cursor: pointer;
+ }
+}
diff --git a/src/components/utils.js b/src/components/utils.js
new file mode 100644
index 0000000..9847108
--- /dev/null
+++ b/src/components/utils.js
@@ -0,0 +1,87 @@
+function walkBookmarksTree(root) {
+ const result = []
+ // 深度优先遍历
+ const walk = (node, list) => {
+ const els = node.children
+ if (els && els.length > 0) {
+ for (let i = 0; i < els.length; i++) {
+ const item = els[i]
+ // p标签或h3标签直接跳过
+ if (item.tagName === 'P' || item.tagName === 'H3') {
+ continue
+ }
+ // 文件夹不用创建元素
+ if (item.tagName === 'DL') {
+ walk(els[i], list)
+ } else { // DT节点
+ let child = null
+ // 判断是否是文件夹
+ const children = item.children
+ let isDir = false
+ for (let j = 0; j < children.length; j++) {
+ if (children[j].tagName === 'H3' || children[j].tagName === 'DL') {
+ isDir = true
+ }
+ }
+ // 文件夹
+ if (isDir) {
+ child = {
+ name: item.tagName === 'DT' ? item.querySelector('h3') ? item.querySelector('h3').innerText : '' : '',
+ folder: true,
+ children: []
+ }
+ walk(els[i], child.children)
+ } else { // 书签
+ const _item = item.querySelector('a')
+ if (_item) {
+ child = {
+ name: _item?.innerText,
+ url: _item?.href
+ }
+ }
+ }
+ child && list.push(child)
+ }
+ }
+ }
+ }
+ walk(root, result)
+ return result
+}
+
+// 导入
+export function importBookmark() {
+ const file = document.getElementById('file')
+ file.dispatchEvent(new MouseEvent('click'))
+ const mybookmark = document.getElementById('mybookmark')
+ document.getElementById('file').addEventListener('change', function () {
+ var file = document.getElementById('file').files[0]
+ var reader = new FileReader()
+ reader.readAsText(file, 'utf-8')
+ reader.onload = function () {
+ mybookmark.innerHTML = reader.result
+ console.log(walkBookmarksTree(mybookmark))
+ // const myData = walkBookmarksTree(mybookmark)
+ // myData && localStorage.setItem('BOOKMARK', myData)
+ }
+ })
+}
+// 导出数据为JSON下载
+export function exportBookmark() {
+ if (localStorage.getItem('BOOKMARK')) {
+ var content = localStorage.getItem('BOOKMARK')
+ var eleLink = document.createElement('a')
+ eleLink.download = 'kestrel-bookmark.json'
+ eleLink.style.display = 'none'
+ // 字符内容转变成blob地址
+ var blob = new Blob([content])
+ eleLink.href = URL.createObjectURL(blob)
+ // 触发点击
+ document.body.appendChild(eleLink)
+ eleLink.click()
+ // 然后移除
+ document.body.removeChild(eleLink)
+ } else {
+ this.$message.warning('暂无可导出数据')
+ }
+}