You've already forked SmartisanNote.Remake
258 lines
6.6 KiB
Vue
258 lines
6.6 KiB
Vue
<template>
|
||
<div class="component">
|
||
<div class="inner code-fun-flex-row code-fun-items-center">
|
||
<!-- 左侧图标 -->
|
||
<img class="left-icon" :src="leftIconSource" @click="handleLeftAction" />
|
||
|
||
<!-- 标题区域 -->
|
||
<div class="title-container">
|
||
<span class="text" @click="handleTitlePress">{{ title }}</span>
|
||
<!-- 文件夹展开图标 -->
|
||
<img v-if="showFolderIcon" class="folder-icon" :src="folderExpanded ? '/assets/icons/drawable-xxhdpi/folder_title_arrow_pressed.png' : '/assets/icons/drawable-xxhdpi/folder_title_arrow_normal.png'" @click.stop="handleFolderToggle" />
|
||
</div>
|
||
|
||
<!-- 右侧操作按钮 -->
|
||
<!-- 新建便签 -->
|
||
<img v-if="actionIcon === 'create'" class="image_4" src="/assets/icons/drawable-xxhdpi/btn_create.png" @click="handleAction('create')" />
|
||
|
||
<!-- 编辑模式 -->
|
||
<div v-else-if="actionIcon === 'edit'" class="code-fun-flex-row code-fun-items-center right-group">
|
||
<!-- 插入图片 -->
|
||
<img class="image_4" src="/assets/icons/drawable-xxhdpi/btn_pic.png" @click="handleAction('insertImage')" />
|
||
<!-- 保存便签 -->
|
||
<img class="image_4" src="/assets/icons/drawable-xxhdpi/btn_save_notes.png" @click="handleAction('save')" />
|
||
</div>
|
||
|
||
<!-- 预览模式 -->
|
||
<div v-else-if="actionIcon === 'preview'" class="code-fun-flex-row code-fun-items-center right-group">
|
||
<!-- 删除便签 -->
|
||
<img
|
||
ref="deleteButtonRef"
|
||
class="image_4"
|
||
:src="deleteButtonFrame"
|
||
@click="handleAction('delete')"
|
||
/>
|
||
<!-- 分享便签 -->
|
||
<img class="image_4" src="/assets/icons/drawable-xxhdpi/btn_share_notes.png" @click="handleAction('share')" />
|
||
</div>
|
||
<!-- 占位符 -->
|
||
<div v-else class="image_4-placeholder"></div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, defineExpose } from 'vue'
|
||
|
||
const props = defineProps({
|
||
title: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
onBack: {
|
||
type: Function,
|
||
default: null,
|
||
},
|
||
onAction: {
|
||
type: Function,
|
||
default: null,
|
||
},
|
||
actionText: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
actionIcon: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
leftIcon: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
leftType: {
|
||
type: String,
|
||
default: 'back',
|
||
},
|
||
onLeftAction: {
|
||
type: Function,
|
||
default: null,
|
||
},
|
||
onFolderToggle: {
|
||
type: Function,
|
||
default: null,
|
||
},
|
||
isFolderExpanded: {
|
||
type: Boolean,
|
||
default: undefined,
|
||
},
|
||
onTitlePress: {
|
||
type: Function,
|
||
default: null,
|
||
},
|
||
background: {
|
||
type: String,
|
||
default: 'url(/assets/icons/drawable-xxhdpi/action_bar_default.png)',
|
||
},
|
||
color: {
|
||
type: String,
|
||
default: 'white',
|
||
},
|
||
})
|
||
|
||
const localFolderExpanded = ref(false)
|
||
const deleteButtonRef = ref(null)
|
||
const deleteButtonFrame = ref('/assets/icons/drawable-xxhdpi/btn_delete_notes.png')
|
||
const isDeleteAnimating = ref(false)
|
||
|
||
const folderExpanded = computed(() => {
|
||
// 优先使用父组件传递的isFolderExpanded状态,否则使用本地状态
|
||
return props.isFolderExpanded !== undefined ? props.isFolderExpanded : localFolderExpanded.value
|
||
})
|
||
|
||
const showFolderIcon = computed(() => {
|
||
// 只有当leftType为settings且有onFolderToggle回调时才显示文件夹图标
|
||
return props.leftType === 'settings' && props.onFolderToggle
|
||
})
|
||
|
||
const leftIconSource = computed(() => {
|
||
// 根据leftType属性返回对应的图标路径
|
||
if (props.leftType === 'settings') {
|
||
return '/assets/icons/drawable-xxhdpi/btn_settings.png'
|
||
} else {
|
||
if (props.color !== 'white') {
|
||
return '/assets/icons/drawable-xxhdpi/btn_back_black.png'
|
||
} else {
|
||
return '/assets/icons/drawable-xxhdpi/btn_back.png'
|
||
}
|
||
}
|
||
})
|
||
|
||
const handleFolderToggle = () => {
|
||
// 切换文件夹展开状态
|
||
if (props.isFolderExpanded === undefined) {
|
||
// 如果父组件没有传递isFolderExpanded,则使用本地状态
|
||
localFolderExpanded.value = !localFolderExpanded.value
|
||
}
|
||
|
||
// 调用父组件传递的回调函数
|
||
if (props.onFolderToggle) {
|
||
props.onFolderToggle()
|
||
}
|
||
}
|
||
|
||
// 播放删除按钮动画(只使用存在的帧)
|
||
const playDeleteAnimation = () => {
|
||
if (isDeleteAnimating.value) return
|
||
|
||
isDeleteAnimating.value = true
|
||
// 只使用存在的帧编号
|
||
const frames = [1, 6, 9, 10, 13, 16, 19, 21, 23, 25, 26, 27, 28, 29, 30]
|
||
let currentFrameIndex = 0
|
||
|
||
const playFrame = () => {
|
||
if (currentFrameIndex < frames.length) {
|
||
// 格式化帧编号(补零)
|
||
const frameNumber = frames[currentFrameIndex].toString().padStart(4, '0')
|
||
deleteButtonFrame.value = `/assets/icons/drawable-xxhdpi/title_bar_del_btn_mov_${frameNumber}.png`
|
||
currentFrameIndex++
|
||
|
||
// 使用setTimeout控制动画播放速度
|
||
setTimeout(playFrame, 50) // 约20fps,调整速度以适应帧数
|
||
} else {
|
||
// 动画播放完成,重置为默认图标
|
||
setTimeout(() => {
|
||
deleteButtonFrame.value = '/assets/icons/drawable-xxhdpi/btn_delete_notes.png'
|
||
isDeleteAnimating.value = false
|
||
}, 100)
|
||
}
|
||
}
|
||
|
||
// 开始播放动画
|
||
playFrame()
|
||
}
|
||
|
||
// 暴露播放删除动画的方法给父组件
|
||
defineExpose({
|
||
playDeleteAnimation
|
||
})
|
||
|
||
const handleLeftAction = () => {
|
||
// 处理左侧图标点击事件
|
||
if (props.onLeftAction) {
|
||
props.onLeftAction()
|
||
} else if (props.leftType !== 'settings' && props.onBack) {
|
||
// 兼容旧版本的onBack属性
|
||
props.onBack()
|
||
}
|
||
}
|
||
|
||
const handleAction = actionType => {
|
||
// 处理右侧操作按钮点击事件
|
||
if (props.onAction) {
|
||
props.onAction(actionType)
|
||
}
|
||
}
|
||
|
||
const handleTitlePress = () => {
|
||
// 处理标题点击事件
|
||
if (props.onTitlePress) {
|
||
props.onTitlePress()
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.component {
|
||
padding: 2.5rem 0.72rem 0.35rem;
|
||
background: v-bind(background);
|
||
background-size: 100% 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
position: relative;
|
||
box-shadow: 0 0 30px 5px rgba(0, 0, 0, 0.2);
|
||
.inner {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
width: 100%;
|
||
}
|
||
.left-icon,
|
||
.image_4 {
|
||
width: 1.9rem;
|
||
height: 1.9rem;
|
||
cursor: pointer;
|
||
}
|
||
.right-group {
|
||
gap: 0.6rem;
|
||
}
|
||
|
||
.image_4-placeholder {
|
||
width: 1.9rem;
|
||
height: 1.9rem;
|
||
}
|
||
|
||
.title-container {
|
||
display: flex;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
flex: 1;
|
||
justify-content: center;
|
||
|
||
.folder-icon {
|
||
width: 0.8rem;
|
||
height: 0.8rem;
|
||
margin-left: 0.2rem;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.text {
|
||
color: v-bind(color);
|
||
font-size: 1.01rem;
|
||
line-height: 1.01rem;
|
||
letter-spacing: 0.05em;
|
||
text-indent: 0.05em;
|
||
}
|
||
}
|
||
}
|
||
</style>
|