feat:新增修改删除书签功能
This commit is contained in:
parent
2c5ba8a454
commit
a3d22a8b60
75
src/App.vue
75
src/App.vue
@ -11,8 +11,7 @@
|
|||||||
<img src="./assets/svg/search.svg">
|
<img src="./assets/svg/search.svg">
|
||||||
<input type="text" placeholder="请输入书签名称" v-model="searchVal" />
|
<input type="text" placeholder="请输入书签名称" v-model="searchVal" />
|
||||||
</div>
|
</div>
|
||||||
<img src="./assets/svg/add.svg" class="tool-icon" @click="add" />
|
<img src="./assets/svg/add.svg" class="tool-icon" @click="add({},'add')" />
|
||||||
|
|
||||||
<a title="我的博客" href="https://zhanhongzhu.top" target="_blank"><img src="./assets/svg/blog.svg" class="tool-icon" /></a>
|
<a title="我的博客" href="https://zhanhongzhu.top" target="_blank"><img src="./assets/svg/blog.svg" class="tool-icon" /></a>
|
||||||
<a title="在线翻译" href="https://translate.google.cn" target="_blank"><img src="./assets/svg/translate.svg" class="tool-icon" /></a>
|
<a title="在线翻译" href="https://translate.google.cn" target="_blank"><img src="./assets/svg/translate.svg" class="tool-icon" /></a>
|
||||||
<a title="我的码云" href="https://gitee.com/zhanhongzhu/kestrel-bookmark" target="_blank"><img src="./assets/svg/gitee.svg" class="tool-icon" /></a>
|
<a title="我的码云" href="https://gitee.com/zhanhongzhu/kestrel-bookmark" target="_blank"><img src="./assets/svg/gitee.svg" class="tool-icon" /></a>
|
||||||
@ -32,8 +31,13 @@
|
|||||||
<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)">
|
||||||
<div class="logo-img"><img :src="card.logo?card.logo:'/img/logo.f38dc2e8.svg'" /></div>
|
<div class="logo-img"><img :src="card.logo?card.logo:'/img/logo.f38dc2e8.svg'" /></div>
|
||||||
<div class="logo-box">
|
<div class="logo-box">
|
||||||
<span class="title">{{card.title}}</span>
|
<span class="logo-box-tools">
|
||||||
<span class="subtitle">{{card.desc}}</span>
|
<i class="el-icon-edit" @click.stop="add(card,'modify')"></i>
|
||||||
|
<i class="el-icon-delete" @click.stop="deleteClick(card)"></i>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="title">{{card.title || 'Kestrel-bookmark'}}</span>
|
||||||
|
<span class="subtitle">{{card.desc || "红隼书签-为中国 Web 前端开发人员提供优质网站导航"}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
@ -55,7 +59,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Dialog class="my-dialog" v-model="isDetailVisible" @closeViews="closeViews" :selectType="activeIndex" @fresh="search"/>
|
<Dialog class="my-dialog" v-model="isDetailVisible" @closeViews="closeViews" :detail="detail" :selectType="activeIndex" @fresh="search" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -64,6 +68,7 @@ import { myData } from './assets/Json/印象笔记.js'
|
|||||||
import { watch } from '@vue/runtime-core'
|
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'
|
||||||
var rowData = []
|
var rowData = []
|
||||||
function getData(fn = () => {}) {
|
function getData(fn = () => {}) {
|
||||||
// 数据持久化
|
// 数据持久化
|
||||||
@ -97,7 +102,8 @@ export default {
|
|||||||
bookMark: rowData[0].children,
|
bookMark: rowData[0].children,
|
||||||
searchVal: '',
|
searchVal: '',
|
||||||
allData: flatten(rowData),
|
allData: flatten(rowData),
|
||||||
isDetailVisible: false
|
isDetailVisible: false,
|
||||||
|
detail: {}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 全部数据筛选功能
|
// 全部数据筛选功能
|
||||||
@ -119,17 +125,43 @@ export default {
|
|||||||
const navigate = (v) => window.open(v.url, '_target')
|
const navigate = (v) => window.open(v.url, '_target')
|
||||||
|
|
||||||
// 新增书签
|
// 新增书签
|
||||||
const add = () => (data.isDetailVisible = !data.isDetailVisible)
|
function add(row = {}, flag = 'add') {
|
||||||
|
const temp = {...row}
|
||||||
|
if (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.isDetailVisible = true
|
||||||
|
}
|
||||||
// 关闭弹窗事件
|
// 关闭弹窗事件
|
||||||
const closeViews = (v) => (data.isDetailVisible = v)
|
const closeViews = (v) => (data.isDetailVisible = v)
|
||||||
|
|
||||||
|
// 获取数据
|
||||||
const search = async () => {
|
const search = async () => {
|
||||||
console.log('---->')
|
|
||||||
await getData(() => {
|
await getData(() => {
|
||||||
|
data.data = rowData
|
||||||
data.bookMark = rowData[data.activeIndex].children
|
data.bookMark = rowData[data.activeIndex].children
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 删除
|
||||||
|
const deleteClick = (row) => {
|
||||||
|
const myData = JSON.parse(localStorage.getItem('BOOKMARK'))
|
||||||
|
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)
|
||||||
|
if (cindex > -1) {
|
||||||
|
myData[i].children.splice(cindex, 1)
|
||||||
|
localStorage.setItem('BOOKMARK', JSON.stringify(myData))
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
search()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
|
deleteClick,
|
||||||
...toRefs(data),
|
...toRefs(data),
|
||||||
selectType,
|
selectType,
|
||||||
navigate,
|
navigate,
|
||||||
@ -251,6 +283,9 @@ 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{
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,7 +364,7 @@ export default {
|
|||||||
.logo-img {
|
.logo-img {
|
||||||
width: 62px;
|
width: 62px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-right: 14px;
|
margin-right: 10px;
|
||||||
img {
|
img {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -340,10 +375,11 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.logo-box {
|
.logo-box {
|
||||||
|
position: relative;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
.title {
|
.title {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 190px;
|
max-width: 145px;
|
||||||
display: block;
|
display: block;
|
||||||
padding-top: 3px;
|
padding-top: 3px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@ -402,4 +438,21 @@ export default {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
background: url(./assets/bg.jpg);
|
background: url(./assets/bg.jpg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logo-box-tools {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition:0.4s opacity;
|
||||||
|
i {
|
||||||
|
padding: 4px;
|
||||||
|
display: inline-block;
|
||||||
|
&:hover {
|
||||||
|
color: #e03b5d;
|
||||||
|
background: #ff00001f;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -41,8 +41,9 @@
|
|||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import gsap from 'gsap'
|
import gsap from 'gsap'
|
||||||
import { reactive, ref } from '@vue/reactivity'
|
import { reactive, ref, toRefs } from '@vue/reactivity'
|
||||||
import { nextTick } from '@vue/runtime-core'
|
import { nextTick, watch } from '@vue/runtime-core'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
export default {
|
export default {
|
||||||
model: {
|
model: {
|
||||||
value: 'isDetailVisible',
|
value: 'isDetailVisible',
|
||||||
@ -56,17 +57,23 @@ export default {
|
|||||||
selectType: {
|
selectType: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
|
},
|
||||||
|
detail: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
const isBOOKMARK = JSON.parse(localStorage.getItem('BOOKMARK'))
|
const isBOOKMARK = JSON.parse(localStorage.getItem('BOOKMARK'))
|
||||||
const BOOKMARK = isBOOKMARK ? isBOOKMARK.map((v) => v.type) : []
|
const BOOKMARK = isBOOKMARK ? isBOOKMARK.map((v) => v.type) : []
|
||||||
const ruleForm = reactive({
|
const form = reactive({
|
||||||
title: '',
|
ruleForm: {
|
||||||
type: '',
|
title: '',
|
||||||
desc: '',
|
type: '',
|
||||||
url: '',
|
desc: '',
|
||||||
logo: ''
|
url: '',
|
||||||
|
logo: ''
|
||||||
|
}
|
||||||
})
|
})
|
||||||
// 定义校验规则 表单代码中必须以 :rules 接收
|
// 定义校验规则 表单代码中必须以 :rules 接收
|
||||||
const rules = {
|
const rules = {
|
||||||
@ -75,37 +82,70 @@ export default {
|
|||||||
}
|
}
|
||||||
const refruleForm = ref(null)
|
const refruleForm = ref(null)
|
||||||
// 确定按钮的格式
|
// 确定按钮的格式
|
||||||
console.log('--->', isBOOKMARK)
|
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
refruleForm.value.validate((valid) => {
|
refruleForm.value.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
console.log(isBOOKMARK)
|
|
||||||
const myData = isBOOKMARK.map((v) => {
|
const myData = isBOOKMARK.map((v) => {
|
||||||
if (v.type === ruleForm.type) {
|
const myDetail = { ...props.detail }
|
||||||
v.children.push({ ...ruleForm })
|
const formData = { ...form.ruleForm }
|
||||||
|
if (props.detail.flag === 'modify') {
|
||||||
|
// 分类没有变
|
||||||
|
if (myDetail.type === formData.type && v.type === formData.type) {
|
||||||
|
const sIndex = v.children.findIndex(
|
||||||
|
(d) => d.title === myDetail.title
|
||||||
|
)
|
||||||
|
if (sIndex > -1) {
|
||||||
|
v.children[sIndex] = formData
|
||||||
|
ElMessage.success('编辑成功')
|
||||||
|
}
|
||||||
|
} else if (myDetail.type !== formData.type) {
|
||||||
|
// 更改了分类
|
||||||
|
// 当前分类删除该数据
|
||||||
|
if (myDetail.type === v.type) {
|
||||||
|
const pindex = v.children.findIndex(p => p.title === myDetail.title)
|
||||||
|
v.children.splice(pindex, 1)
|
||||||
|
}
|
||||||
|
// 新分类添加该分类
|
||||||
|
if (formData.type === v.type) {
|
||||||
|
v.children.push(formData)
|
||||||
|
ElMessage.success('编辑成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 新增书签
|
||||||
|
console.log('---?')
|
||||||
|
if (v.type === formData.type) {
|
||||||
|
v.children.push(formData)
|
||||||
|
ElMessage.success('新增成功')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
})
|
})
|
||||||
console.log(myData)
|
|
||||||
localStorage.setItem('BOOKMARK', JSON.stringify(myData))
|
localStorage.setItem('BOOKMARK', JSON.stringify(myData))
|
||||||
context.emit('fresh')
|
context.emit('fresh')
|
||||||
closeViews()
|
closeViews()
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 关闭弹窗
|
||||||
function closeViews() {
|
function closeViews() {
|
||||||
refruleForm.value.resetFields()
|
refruleForm.value.resetFields()
|
||||||
context.emit('closeViews', false)
|
context.emit('closeViews', false)
|
||||||
}
|
}
|
||||||
// 书签类别
|
// 修改书签
|
||||||
nextTick(() => {
|
watch(
|
||||||
ruleForm.type = isBOOKMARK ? BOOKMARK[props.selectType] : ''
|
() => props.detail,
|
||||||
})
|
(v) => {
|
||||||
|
if (v) {
|
||||||
|
nextTick(() => {
|
||||||
|
form.ruleForm = { ...props.detail }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
ruleForm,
|
...toRefs(form),
|
||||||
closeViews,
|
closeViews,
|
||||||
submitForm,
|
submitForm,
|
||||||
refruleForm,
|
refruleForm,
|
||||||
|
Loading…
Reference in New Issue
Block a user