目录
01: 文件下载解决方案
想要实现下载图片功能,需要使用到专门的下载包。
目前常用的支持下载功能的包有两个:
1. 小文件下载:file-saver
2. 大文件下载:streamsaver
咱们的图片下载属于小文件的下载,所以我们直接使用 file-saver。
1. 安装 file-saver
npm i --save file-saver@2.0.5
2. 在 src/views/main/components/list/item.vue 中,增加下载功能:
<script setup>
import { saveAs } from 'file-saver'
/**
* 下载按钮点击事件
*/
const onDownload = () => {
// 提示消息
message('success', '图片开始下载')
// 延迟一段时间执行,可以得到更好的体验
setTimeout(() => {
/**
* 接收两个参数:
* 1. 下载的图片链接
* 2. 下载的文件名称
*/
saveAs(
props.data.photoDownLink,
`${props.data.title} - 作者:${props.data.author}`
)
}, 100)
}
02: 通用组件:方法触发的 message 构建分析
之前的时候,我们构建过一个 confirm 的通用组件,该组件我们可以直接通过 方法进行调用展示。
对于接下来打算构建的 message 组件,我们依然希望可以通过方法的调用直接展示对应的组件。
根据我们之前的经验,可以知道:
1. 首先我们需要先构建出一个对应的 message.vue
2. 然后构建出对应的 message.js 模块
3. 在模块中,通过:
1. h 函数构建 vnode
2. render 函数,进行渲染
依次进行处理。以上方式,就是咱们 message 的构建过程。
03: 通用组件:构建 message 组件基本能力
- src/libs
- - message
- - - index.vue
- - - index.js
<template>
<transition name="down" @after-leave="destroy">
<div
v-show="isVisable"
class="min-w-[420px] fixed top-[20px] left-[50%] translate-x-[-50%] z-50 flex items-center px-3 py-1.5 rounded-sm border cursor-pointer"
:class="styles[type].containerClass"
>
<m-svg-icon
:name="styles[type].icon"
:fillClass="styles[type].fillClass"
class="h-1.5 w-1.5 mr-1.5"
></m-svg-icon>
<span class="text-sm" :class="styles[type].textClass">
{{ content }}
</span>
</div>
</transition>
</template>
<script>
import mSvgIcon from '../svg-icon/index.vue'
/**
* 消息类型可选项
*/
const typeEnum = ['success', 'warn', 'error']
</script>
<script setup>
import { ref, onMounted } from 'vue'
const props = defineProps({
/**
* message 的消息类型
*/
type: {
type: String,
required: true,
validator(val) {
const result = typeEnum.includes(val)
if (!result) {
throw new Error(`你的 type 必须是 ${typeEnum.join('、')} 中的一个`)
}
return result
}
},
/**
* 描述文本
*/
content: {
type: String,
required: true
},
/**
* 展示时长
*/
duration: {
type: Number
},
/**
* 关闭时的回调
*/
destroy: {
type: Function
}
})
// 样式表数据
const styles = {
// 警告
warn: {
icon: 'warn',
fillClass: 'fill-warn-300',
textClass: 'text-warn-300',
containerClass:
'bg-warn-100 border-warn-200 hover:shadow-lg hover:shadow-warn-100'
},
// 错误
error: {
icon: 'error',
fillClass: 'fill-error-300',
textClass: 'text-error-300',
containerClass:
'bg-error-100 border-error-200 hover:shadow-lg hover:shadow-error-100'
},
// 成功
success: {
icon: 'success',
fillClass: 'fill-success-300',
textClass: 'text-success-300',
containerClass:
'bg-success-100 border-success-200 hover:shadow-lg hover:shadow-success-100'
}
}
// 控制显示处理
const isVisable = ref(false)
// 关闭前 动画执行时间
const animDuration = '0.5s'
/**
* 保证动画展示,需要在 mounted 之后进行展示
*/
onMounted(() => {
isVisable.value = true
/**
* 延迟时间关闭
*/
setTimeout(() => {
isVisable.value = false
setTimeout(() => {
if (props.destory) {
props.destory()
}
}, parseInt(duration.replace('0.', '').replace('s', '') * 100))
}, props.duration)
})
</script>
<style lang="scss" scoped>
.down-enter-active,
.down-leave-active {
transition: all v-bind(animDuration);
}
.down-enter-from,
.down-leave-to {
opacity: 0;
transform: translate3d(-50%, -100px, 0);
}
</style>
04: 通用组件:方法触发 message 展示
// src/libs/message/index.js
import { h, render } from 'vue'
import messageComponent from './index.vue'
export const message = (type, content, duration = 3000) => {
/**
* 动画结束时的回调
*/
const onDestroy = () => {
// 3. message 销毁
render(null, document.body)
}
// 1. 返回 vnode
const vnode = h(messageComponent, {
type,
content,
duration,
destroy: onDestroy
})
// 2. render
render(vnode, document.body)
}
05: 模块全屏解决方案
让页面中的指定区域进行全屏展示也是非常常见的一个功能。想要让页面的指定区域进行全屏展示,我们通常可以使用 全屏API,该 API 中提供了两个方法:
1. Element.requestFullscreen(): 让指定元素进行全屏。
2. Document.exitFullscreen(): 退出全屏。
但是这个 API 比较原始,使用起来没有那么方便,所以我们可以使用一个 vueuse 中更加简便的 API:useFullScreen。
使用 useFullScreen 生成 img 图片的全屏方法:
<script setup>
import { useFullscreen } from '@vueuse/core'
const imgTarget = ref(null)
/**
* 生成全屏方法
*/
const { enter: onImgFullScreen } = useFullscreen(imgTarget)
</script>
<template>
<m-button @click="onImgFullScreen" />
</template>
06: 构建 floating 基础布局
- src/views/layout/components
- - floating
- - - index.vue
<template>
<div class="fixed bottom-10 right-2">
<!-- 引导页 -->
<div
class="guide-start w-4 h-4 mb-1 bg-white dark:bg-zinc-900 border dark:border-0 border-zinc-200 rounded-full flex justify-center items-center cursor-pointer duration-200 group hover:shadow-lg"
@click="onGuideClick"
>
<m-svg-icon
name="guide"
class="w-2 h-2"
fillClass="fill-zinc-900 dark:fill-zinc-200 group-hover:fill-main "
></m-svg-icon>
</div>
<!-- 反馈 -->
<m-popover class="flex items-center guide-feedback" placement="top-left">
<template #reference>
<div
class="w-4 h-4 bg-white dark:bg-zinc-900 border dark:border-0 border-zinc-200 rounded-full flex justify-center items-center cursor-pointer duration-200 group hover:shadow-lg"
>
<m-svg-icon
name="feedback"
class="w-2 h-2"
fillClass="fill-zinc-900 dark:fill-zinc-200 group-hover:fill-main "
></m-svg-icon>
</div>
</template>
<div class="w-[140px] overflow-hidden">
<div
class="flex items-center p-1 cursor-pointer rounded hover:bg-zinc-100/60 dark:hover:bg-zinc-800"
@click="onToFeedback"
>
<m-svg-icon
name="feedback"
class="w-1.5 h-1.5 mr-1"
fillClass="fill-zinc-900 dark:fill-zinc-300"
></m-svg-icon>
<span class="text-zinc-800 dark:text-zinc-300 text-sm">立即吐槽</span>
</div>
</div>
</m-popover>
</div>
</template>
<script setup>
import Driver from 'driver.js'
import 'driver.js/dist/driver.min.css'
import steps from './steps'
import { onMounted } from 'vue'
import { FEEDBACK_URL } from '@/constants'
/**
* 引导页处理
*/
let driver = null
onMounted(() => {
driver = new Driver({
// 禁止点击蒙版关闭
allowClose: false,
closeBtnText: '关闭',
nextBtnText: '下一个',
prevBtnText: '上一个'
})
})
/**
* 开始引导
*/
const onGuideClick = () => {
driver.defineSteps(steps)
driver.start()
}
/**
* 反馈处理
*/
const onToFeedback = () => {
window.open(FEEDBACK_URL, '_blank')
}
</script>
<style lang="scss" scoped>
.driver-fix-stacking {
position: fixed;
z-index: 100004 !important;
}
</style>
07: 样式修正:处理难看的 scrollBar
scrollBar 看着实在是有点难看,接下来就需要修正一下这个 scrollBar 的样式。
对于 tailwind 而言,默认没有提供 scrollBar 的样式类名。想要处理 scrollBar 的样式,需要安装单独的插件:tailwind-scrollbar。
1. 安装插件
npm install --save-dev tailwind-scrollbar@1.3.1
2. 在 tailwind.config.js 中注册该插件
plugins: [require('tailwind-scrollbar')]
3. 在 tailwind.config.js 中,让 scrollBar 支持 dark 模式
module.exports = {
……
theme: {
extend: {
……
variants: {
scrollbar: ['dark']
}
}
}
……
}
4. 在 src/views/min/index.vue 中使用
scrollbar-thin
scrollbar-thumb-transparent
xl:scrollbar-thumb-zinc-200
xl:dark:scrollbar-thumb-zinc-900
scrollbar-track-transparent
scrollbar-thumb-transparent // 滚道样式
5. 在 src/libs/search/index.vue 中使用
scrollbar-thin
scrollbar-thumb-zinc-200
dark:scrollbar-thumb-zinc-900
scrollbar-track-transparent
6. 补充 边弧度 样式
/* src/styles/index.scss */
::-webkit-scrollbar-thumb {
border-radius: 10px;
}
08: 功能引导解决方案
想要完成功能引导的实现,我们需要借助一个第三方包:driver.js
下面我们就使用这个第三方包来实现咱们的功能引导:
1. 安装 driver.js
npm install --save driver.js@0.9.8
2. 在 src/views/layout/components/floating/index.vue 中导入对应模块
import Driver from 'driver.js'
import 'driver.js/dist/driver.min.css'
3. 初始化 Driver
/**
* 引导页处理
*/
let driver = null
onMounted(() => {
driver = new Driver({
// 禁止点击蒙版关闭
allowClose: false,
closeBtnText: '关闭',
nextBtnText: '下一个',
prevBtnText: '上一个'
})
})
4. 构建引导步骤
// src/views/layout/components/steps.js
export default [
{
// 在哪个元素中高亮
element: '.guide-home',
// 配置对象
popover: {
// 标题
title: 'logo',
// 描述
description: '点击可返回首页'
}
},
{
element: '.guide-search',
popover: {
title: '搜索',
description: '搜索您期望的图片'
}
},
{
element: '.guide-theme',
popover: {
title: '风格',
description: '选择一个您喜欢的风格',
// 弹出的位置
position: 'left'
}
},
{
element: '.guide-my',
popover: {
title: '账户',
description: '这里标记了您的账户信息',
position: 'left'
}
},
{
element: '.guide-start',
popover: {
title: '引导',
description: '这里可再次查看引导信息',
position: 'left'
}
},
{
element: '.guide-feedback',
popover: {
title: '反馈',
description: '您的任何不满都可以在这里告诉我们',
position: 'left'
}
}
]
使用:
<script setup>
import steps from './steps'
/**
* 开始引导
*/
const onGuideClick = () => {
driver.defineSteps(steps)
driver.start()
}
</script>
09: 解决功能引导图标不显示的问题
/* src/styles/index.scss */
.driver-fix-stacking {
position: relative;
}
.driver-navigation-btns {
line-height: 0;
}
// src/views/layout/components/floating/index.vue
<style lang="scss" scoped>
.driver-fix-stacking {
position: fixed;
z-index: 100004 !important;
}
</style>
10: 总结
本篇文章中,我们处理了4个核心功能:
1. 文件下载
2. 通用组件:message 构建
3. 全屏处理
4. 引导处理