no message
This commit is contained in:
parent
e0a2d6e0dd
commit
a6902abac2
@ -24,7 +24,10 @@
|
|||||||
</noscript>
|
</noscript>
|
||||||
<!-- 内容区域 -->
|
<!-- 内容区域 -->
|
||||||
<div id="app" style="height: 100%;">
|
<div id="app" style="height: 100%;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 导出内容的节点 -->
|
||||||
|
<div id="mybookmark" style="height: 100%;display: none;opacity: 0;">
|
||||||
</div>
|
</div>
|
||||||
<!-- 渐变背景 -->
|
<!-- 渐变背景 -->
|
||||||
<canvas id="canvas-complex"
|
<canvas id="canvas-complex"
|
||||||
|
91
src/App.vue
91
src/App.vue
@ -4,7 +4,7 @@
|
|||||||
<div class="bookmark" id="bookmark">
|
<div class="bookmark" id="bookmark">
|
||||||
<div class="tool-bar">
|
<div class="tool-bar">
|
||||||
<div class="tool-logo">
|
<div class="tool-logo">
|
||||||
<a href="" target="_blank"><img src="./assets/svg/logo.svg" title="更多数据" class="tool-icon" />红隼书签</a>
|
<a href="" target="_blank"><img src="./assets/svg/logo.svg" title="感谢作者 是半夏鸭 设计的图标" class="tool-icon" />红隼书签</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="search-box">
|
<div class="search-box">
|
||||||
@ -21,11 +21,21 @@
|
|||||||
<!-- 侧边导航栏 -->
|
<!-- 侧边导航栏 -->
|
||||||
<div class="box-m">
|
<div class="box-m">
|
||||||
<div class="left-box">
|
<div class="left-box">
|
||||||
|
<div class="left-box-item">
|
||||||
<div class="label" :class="activeIndex===index?'active':'inactive'" v-for="(item,index) in data" :key="index" @click="selectType(item,index)">
|
<div class="label" :class="activeIndex===index?'active':'inactive'" v-for="(item,index) in data" :key="index" @click="selectType(item,index)">
|
||||||
<img src="./assets/svg/file.svg" />
|
<img src="./assets/svg/file.svg" />
|
||||||
<div class="text-elipss"> {{item.type}} </div>
|
<div class="text-elipss"> {{item.type}} </div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 导入导出 -->
|
||||||
|
<div class="import-tool">
|
||||||
|
<span class="import-text">导入/导出: </span>
|
||||||
|
<i class="el-icon-upload2" title="导入浏览器书签" @click="importBookmark">
|
||||||
|
<input type="file" ref="filElem" id="file">
|
||||||
|
</i>
|
||||||
|
<i class="el-icon-download" title="导出浏览器书签" @click="exportBookmark"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="right-box">
|
<div class="right-box">
|
||||||
<transition-group v-if="bookMark.length" name="staggered-fade" class="card-s" tag="ul" :css="false" @before-enter="beforeEnter" @enter="enter" @leave="leave">
|
<transition-group v-if="bookMark.length" name="staggered-fade" class="card-s" tag="ul" :css="false" @before-enter="beforeEnter" @enter="enter" @leave="leave">
|
||||||
<div class="card-item list-complete-item" v-for="(card,idx) in bookMark" :key="idx" @click="navigate(card)">
|
<div class="card-item list-complete-item" v-for="(card,idx) in bookMark" :key="idx" @click="navigate(card)">
|
||||||
@ -69,6 +79,7 @@ import { watch } from '@vue/runtime-core'
|
|||||||
import Dialog from './components/Dialog.vue'
|
import Dialog from './components/Dialog.vue'
|
||||||
import gsap from 'gsap'
|
import gsap from 'gsap'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { importBookmark, exportBookmark } from './components/utils.js'
|
||||||
var rowData = []
|
var rowData = []
|
||||||
function getData(fn = () => {}) {
|
function getData(fn = () => {}) {
|
||||||
// 数据持久化
|
// 数据持久化
|
||||||
@ -126,11 +137,17 @@ export default {
|
|||||||
|
|
||||||
// 新增书签
|
// 新增书签
|
||||||
function add(row = {}, flag = 'add') {
|
function add(row = {}, flag = 'add') {
|
||||||
const temp = {...row}
|
const temp = { ...row }
|
||||||
if (flag === 'modify') {
|
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 {
|
} 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
|
data.isDetailVisible = true
|
||||||
}
|
}
|
||||||
@ -147,10 +164,14 @@ export default {
|
|||||||
// 删除
|
// 删除
|
||||||
const deleteClick = (row) => {
|
const deleteClick = (row) => {
|
||||||
const myData = JSON.parse(localStorage.getItem('BOOKMARK'))
|
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++) {
|
for (let i = 0; i < myData.length; i++) {
|
||||||
if (delDetail.type === myData[i].type) {
|
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) {
|
if (cindex > -1) {
|
||||||
myData[i].children.splice(cindex, 1)
|
myData[i].children.splice(cindex, 1)
|
||||||
localStorage.setItem('BOOKMARK', JSON.stringify(myData))
|
localStorage.setItem('BOOKMARK', JSON.stringify(myData))
|
||||||
@ -167,7 +188,9 @@ export default {
|
|||||||
navigate,
|
navigate,
|
||||||
add,
|
add,
|
||||||
closeViews,
|
closeViews,
|
||||||
search
|
search,
|
||||||
|
importBookmark,
|
||||||
|
exportBookmark
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -218,7 +241,7 @@ export default {
|
|||||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||||
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
|
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow-y: auto;
|
// overflow-y: auto;
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
img {
|
img {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
@ -283,7 +306,7 @@ export default {
|
|||||||
animation: 0.3ms;
|
animation: 0.3ms;
|
||||||
box-shadow: 0 8px 18px 0 rgba(31, 38, 135, 0.3);
|
box-shadow: 0 8px 18px 0 rgba(31, 38, 135, 0.3);
|
||||||
}
|
}
|
||||||
&:hover .logo-box-tools{
|
&:hover .logo-box-tools {
|
||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -444,7 +467,7 @@ export default {
|
|||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition:0.4s opacity;
|
transition: 0.4s opacity;
|
||||||
i {
|
i {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
display: inline-block;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
87
src/components/utils.js
Normal file
87
src/components/utils.js
Normal file
@ -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('暂无可导出数据')
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user