块设备驱动3--sd卡驱动2(linux-3.2.36的host.h分析)

本文档详细介绍了Linux内核中用于块设备驱动的mmc/host.h头文件,包括mmc_ios结构体的各个字段及其在SD卡驱动中的作用。内容涉及时钟速度、电压、数据总线宽度等关键参数的设置,以及mmc_host_ops结构体中各成员函数的功能和调用流程。此外,还讨论了电源管理、时序规范和信号电压等概念。
/*
 *  linux/include/linux/mmc/host.h
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *  Host driver specific definitions.
 */
#ifndef LINUX_MMC_HOST_H
#define LINUX_MMC_HOST_H

#include <linux/leds.h>
#include <linux/sched.h>
#include <linux/fault-inject.h>

#include <linux/mmc/core.h>
#include <linux/mmc/pm.h>

//struct mmc_ios主要是通过mmc_set_ios()调用host->ops->set_ios()
//set_ios()由驱动提供,所以这些结构由host驱动处理,core只管用
struct mmc_ios {
	unsigned int	clock;			/* clock rate */ //时钟速度
	unsigned short	vdd; //电压

/* vdd stores the bit number of the selected voltage range from below. */

	unsigned char	bus_mode;		/* command output mode */
//这是io口的类型,对于我这个电气自动化学生还是懂点的,不过不细说了
#define MMC_BUSMODE_OPENDRAIN	1 //开漏
#define MMC_BUSMODE_PUSHPULL	2 //推挽

	unsigned char	chip_select;		/* SPI chip select */

#define MMC_CS_DONTCARE		0 //不关心
#define MMC_CS_HIGH		1 //高速
#define MMC_CS_LOW		2 //低速
/*
        if (mmc_host_is_spi(host))
                host->ios.chip_select = MMC_CS_HIGH;
        else
                host->ios.chip_select = MMC_CS_DONTCARE;
*/

	unsigned char	power_mode;		/* power supply mode */

#define MMC_POWER_OFF		0//关
#define MMC_POWER_UP		1//开
#define MMC_POWER_ON		2//也是开,s3c2440处理和up一样

	unsigned char	bus_width;		/* data bus width */ //数据总线宽度

#define MMC_BUS_WIDTH_1		0 //1位
#define MMC_BUS_WIDTH_4		2 //4位
#define MMC_BUS_WIDTH_8		3 //8位

	unsigned char	timing;			/* timing specification used */ //时序规范使用

#define MMC_TIMING_LEGACY	0 //旧的
#define MMC_TIMING_MMC_HS	1 //mmc
#define MMC_TIMING_SD_HS	2 //sd
//UHS:超高速版。UHS-I: 超高速版1
//UHS是一种速度标准。
//下面是UHS-I的5种模式,在SDHCI标准中有个叫Host Control 2的寄存器
//它的第0~2位就是选择UHS的模式
#define MMC_TIMING_UHS_SDR12	MMC_TIMING_LEGACY
#define MMC_TIMING_UHS_SDR25	MMC_TIMING_SD_HS
#define MMC_TIMING_UHS_SDR50	3
#define MMC_TIMING_UHS_SDR104	4
#define MMC_TIMING_UHS_DDR50	5

#define MMC_SDR_MODE		0
#define MMC_1_2V_DDR_MODE	1
#define MMC_1_8V_DDR_MODE	2

	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */ 
//上面说信号电压(1.8v 或 3.3v),没有提到1.2v
//我看了SDHCI,还是Host Control 2的第3位 1: 1.8v 0: 3.3v
//也没提到1.2v. 不过代码中提到eMMC卡可以支持1.2v或3.3v
//eMMC:(Embedded Multi Media Card),这东西的封装是:小型的
//BGA 封装。
#define MMC_SIGNAL_VOLTAGE_330	0
#define MMC_SIGNAL_VOLTAGE_180	1
#define MMC_SIGNAL_VOLTAGE_120	2

	unsigned char	drv_type;		/* driver type (A, B, C, D) */
//还是Host Control 2寄存器的4~5位选择,默认是B
//UHS-I卡1.8v时才有效,3.3v无效
//还有Preset Value Enable = 0时可以被主机设置
//Preset Value Enable = 1时由Preset Value寄存器决定
/*
B:默认的驱动。50欧姆传输线阻抗。支持UHS104和UHS50卡。下面的都以B为参考。
A:x1.5驱动(是50/1.5 = 33欧姆)。支持208MHz
C:x0.75。支持208MHz的最弱驱动。
D:x0.5。这个主要是速度不是要紧的,重要是低noise,低EMI。最大频率由主机设计确定。
*/
#define MMC_SET_DRIVER_TYPE_B	0
#define MMC_SET_DRIVER_TYPE_A	1
#define MMC_SET_DRIVER_TYPE_C	2
#define MMC_SET_DRIVER_TYPE_D	3
};

//下面是写驱动要搞定的接口,如果你的硬件支持SDHCI。你可能看不到这个。
//已在sdhci.c统一实现。
struct mmc_host_ops {
	/*
	 * Hosts that support power saving can use the 'enable' and 'disable'
	 * methods to exit and enter power saving states. 'enable' is called
	 * when the host is claimed and 'disable' is called (or scheduled with
	 * a delay) when the host is released. The 'disable' is scheduled if
	 * the disable delay set by 'mmc_set_disable_delay()' is non-zero,
	 * otherwise 'disable' is called immediately. 'disable' may be
	 * scheduled repeatedly, to permit ever greater power saving at the
	 * expense of ever greater latency to re-enable. Rescheduling is
	 * determined by the return value of the 'disable' method. A positive
	 * value gives the delay in milliseconds.
	 *
	 * In the case where a host function (like set_ios) may be called
	 * with or without the host claimed, enabling and disabling can be
	 * done directly and will nest correctly. Call 'mmc_host_enable()' and
	 * 'mmc_host_lazy_disable()' for this purpose, but note that these
	 * functions must be paired.
	 *
	 * Alternatively, 'mmc_host_enable()' may be paired with
	 * 'mmc_host_disable()' which calls 'disable' immediately.  In this
	 * case the 'disable' method will be called with 'lazy' set to 0.
	 * This is mainly useful for error paths.
	 *
	 * Because lazy disable may be called from a work queue, the 'disable'
	 * method must claim the host when 'lazy' != 0, which will work
	 * correctly because recursion is detected and handled.
	 */
	/*
	上面解释了一大堆,自己看看。我说一下调用过程。at91_mci.c sd卡
	at91_mci_driver->at91_mci_suspend()->mmc_suspend_host()->
<think>我们将使用v-viewer库在Vue3中实现一个功能丰富的图片查看器。v-viewer是一个基于viewer.js的Vue图片查看器组件,支持旋转、缩放、翻转、播放等操作。 步骤: 1. 安装v-viewer和viewer.js 2. 在Vue3中全局注册v-viewer组件 3. 创建图片列表并使用v-viewer组件 4. 实现单击图片查看当前图片,并支持从第一张开始查看 代码实现:</think># Vue3中使用v-viewer实现高级图片预览功能 下面我将展示如何在Vue3中使用v-viewer库实现一个功能丰富的图片预览组件,支持单击预览、多图导航、缩放旋转等高级功能。 ## 解决方案思路 1. 安装并配置v-viewer库 2. 创建图片列表组件 3. 实现单图预览和全图集预览功能 4. 添加自定义操作按钮(旋转、缩放、下载等) 5. 实现响应式设计和加载状态处理 ## 完整代码实现 ```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue3 + v-viewer 高级图片预览</title> <!-- 引入v-viewer样式 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/viewerjs@1.11.1/dist/viewer.min.css"> <script src="https://cdn.jsdelivr.net/npm/vue@3.2.36/dist/vue.global.js"></script> <script src="https://cdn.jsdelivr.net/npm/viewerjs@1.11.1/dist/viewer.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/v-viewer@1.6.4/dist/index.min.js"></script> <style> :root { --primary: #4361ee; --secondary: #3f37c9; --accent: #4895ef; --light: #f8f9fa; --dark: #212529; --success: #4cc9f0; --warning: #f72585; --gray: #6c757d; --border: #dee2e6; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: &#39;Segoe UI&#39;, Tahoma, Geneva, Verdana, sans-serif; } body { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); min-height: 100vh; padding: 20px; color: var(--dark); } .container { max-width: 1400px; margin: 40px auto; background: white; border-radius: 20px; box-shadow: 0 15px 50px rgba(0, 0, 0, 0.15); overflow: hidden; } header { background: linear-gradient(to right, var(--primary), var(--secondary)); color: white; padding: 30px 40px; text-align: center; } h1 { font-size: 2.8rem; margin-bottom: 15px; text-shadow: 0 2px 4px rgba(0,0,0,0.2); } .subtitle { font-size: 1.2rem; opacity: 0.9; max-width: 700px; margin: 0 auto; } .content { padding: 40px; } .features { display: flex; flex-wrap: wrap; justify-content: center; gap: 25px; margin: 40px 0; } .feature-card { width: 220px; padding: 25px; background: white; border-radius: 15px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08); text-align: center; transition: all 0.3s ease; border: 2px solid transparent; } .feature-card:hover { transform: translateY(-10px); box-shadow: 0 12px 20px rgba(67, 97, 238, 0.15); border-color: var(--accent); } .feature-icon { font-size: 48px; margin-bottom: 20px; color: var(--primary); } .feature-title { font-size: 1.3rem; margin-bottom: 10px; color: var(--dark); } .controls { display: flex; justify-content: center; gap: 20px; margin: 30px 0; flex-wrap: wrap; } .btn { padding: 14px 32px; font-size: 1.1rem; border-radius: 50px; border: none; cursor: pointer; transition: all 0.3s; font-weight: 600; display: inline-flex; align-items: center; gap: 10px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } .btn-primary { background: linear-gradient(to right, var(--primary), var(--accent)); color: white; } .btn-primary:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(67, 97, 238, 0.3); } .btn-secondary { background: white; color: var(--primary); border: 2px solid var(--primary); } .btn-secondary:hover { background: var(--light); } .gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 25px; margin: 40px 0; } .gallery-item { border-radius: 15px; overflow: hidden; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1); cursor: pointer; transition: all 0.3s ease; position: relative; height: 240px; } .gallery-item:hover { transform: translateY(-8px); box-shadow: 0 15px 30px rgba(67, 97, 238, 0.2); } .gallery-img { width: 100%; height: 100%; object-fit: cover; display: block; } .image-info { position: absolute; bottom: 0; left: 0; right: 0; background: rgba(0, 0, 0, 0.7); color: white; padding: 15px; transform: translateY(100%); transition: transform 0.3s ease; } .gallery-item:hover .image-info { transform: translateY(0); } .image-title { font-size: 1.2rem; margin-bottom: 5px; } .image-desc { font-size: 0.9rem; opacity: 0.8; } .status-bar { display: flex; justify-content: space-between; background: var(--light); padding: 15px 25px; border-radius: 12px; margin-top: 30px; font-size: 1.1rem; } footer { text-align: center; padding: 30px; background: var(--light); color: var(--gray); font-size: 1.1rem; } .custom-viewer { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 9999; background: rgba(0, 0, 0, 0.9); } .tech-stack { display: flex; justify-content: center; gap: 20px; margin: 30px 0; flex-wrap: wrap; } .tech-item { background: rgba(67, 97, 238, 0.1); color: var(--primary); padding: 8px 20px; border-radius: 30px; font-weight: 600; display: flex; align-items: center; gap: 8px; } @media (max-width: 768px) { .gallery { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); } h1 { font-size: 2.2rem; } } </style> </head> <body> <div id="app"> <div class="container"> <header> <h1>Vue3 + v-viewer 高级图片预览</h1> <p class="subtitle">实现单图预览、多图导航、缩放旋转等高级功能</p> <div class="tech-stack"> <div class="tech-item">Vue 3</div> <div class="tech-item">v-viewer</div> <div class="tech-item">Viewer.js</div> <div class="tech-item">CSS3</div> </div> </header> <div class="content"> <div class="features"> <div class="feature-card"> <div class="feature-icon">🔍</div> <h3 class="feature-title">缩放查看</h3> <p>支持鼠标滚轮缩放图片</p> </div> <div class="feature-card"> <div class="feature-icon">🔄</div> <h3 class="feature-title">旋转翻转</h3> <p>支持任意角度旋转和水平翻转</p> </div> <div class="feature-card"> <div class="feature-icon">📷</div> <h3 class="feature-title">全屏模式</h3> <p>支持全屏查看图片细节</p> </div> <div class="feature-card"> <div class="feature-icon">⬇️</div> <h3 class="feature-title">下载图片</h3> <p>一键下载原始图片</p> </div> </div> <div class="controls"> <button class="btn btn-primary" @click="viewAll"> <span>查看全部图片</span> </button> <button class="btn btn-secondary" @click="shuffleImages"> <span>随机排序图片</span> </button> </div> <div class="gallery"> <div v-for="(image, index) in images" :key="image.id" class="gallery-item" @click="viewImage(index)" > <img :src="image.thumbnail" :alt="image.title" class="gallery-img"> <div class="image-info"> <div class="image-title">{{ image.title }}</div> <div class="image-desc">{{ image.desc }}</div> </div> </div> </div> <div class="status-bar"> <div>图片数量: {{ images.length }} 张</div> <div>当前预览模式: {{ previewMode }}</div> <div>最后操作: {{ lastAction || &#39;无&#39; }}</div> </div> </div> <footer> Vue3 + v-viewer 图片预览组件 | 支持高级图片查看功能 </footer> </div> <!-- v-viewer 组件 --> <viewer :images="previewList" :options="viewerOptions" @inited="viewerInited" ref="viewerRef"> <template #default="scope"> <div v-for="(src, index) in scope.images" :key="index" style="display: none;"> <img :src="src" :data-source="src"> </div> </template> </viewer> </div> <script> const { createApp, ref, reactive, computed, onMounted } = Vue; const app = createApp({ setup() { // 图片数据 const images = ref([ { id: 1, thumbnail: &#39;https://images.unsplash.com/photo-1682687220067-dced9a881b56?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=400&#39;, full: &#39;https://images.unsplash.com/photo-1682687220067-dced9a881b56?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=1200&#39;, title: &#39;山间日出&#39;, desc: &#39;清晨的第一缕阳光穿过山谷&#39; }, { id: 2, thumbnail: &#39;https://images.unsplash.com/photo-1682687220208-22d7a2543e88?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=400&#39;, full: &#39;https://images.unsplash.com/photo-1682687220208-22d7a2543e88?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=1200&#39;, title: &#39;沙漠风光&#39;, desc: &#39;无垠沙丘与蓝天相接&#39; }, { id: 3, thumbnail: &#39;https://images.unsplash.com/photo-1682687220923-471809f7e9c0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=400&#39;, full: &#39;https://images.unsplash.com/photo-1682687220923-471809f7e9c0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=1200&#39;, title: &#39;海滩日落&#39;, desc: &#39;夕阳下的金色海岸线&#39; }, { id: 4, thumbnail: &#39;https://images.unsplash.com/photo-1682687220509-61b8a906ca19?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=400&#39;, full: &#39;https://images.unsplash.com/photo-1682687220509-61b8a906ca19?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=1200&#39;, title: &#39;森林小径&#39;, desc: &#39;绿意盎然的林间小路&#39; }, { id: 5, thumbnail: &#39;https://images.unsplash.com/photo-1682687220509-61b8a906ca19?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=400&#39;, full: &#39;https://images.unsplash.com/photo-1682687220509-61b8a906ca19?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=1200&#39;, title: &#39;雪山湖泊&#39;, desc: &#39;雪山倒映在清澈湖水中&#39; }, { id: 6, thumbnail: &#39;https://images.unsplash.com/photo-1682687220509-61b8a906ca19?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=400&#39;, full: &#39;https://images.unsplash.com/photo-1682687220509-61b8a906ca19?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY5MTY0NjQ1MQ&ixlib=rb-4.0.3&q=80&w=1200&#39;, title: &#39;城市夜景&#39;, desc: &#39;灯火辉煌的都市夜晚&#39; } ]); // 预览状态 const previewMode = ref(null); const lastAction = ref(null); const viewerRef = ref(null); // 计算预览列表 const previewList = computed(() => { return images.value.map(img => img.full); }); // Viewer.js 配置选项 const viewerOptions = reactive({ inline: false, button: true, navbar: true, title: true, toolbar: { zoomIn: 1, zoomOut: 1, oneToOne: 1, reset: 1, prev: 1, play: { show: 1, size: &#39;large&#39;, }, next: 1, rotateLeft: 1, rotateRight: 1, flipHorizontal: 1, flipVertical: 1, }, viewed(ev) { lastAction.value = `查看图片: ${images.value[ev.detail.index].title}`; }, rotate(ev) { lastAction.value = `旋转图片: ${ev.detail.degree}°`; }, flip(ev) { lastAction.value = `翻转图片: ${ev.detail.direction === &#39;horizontal&#39; ? &#39;水平&#39; : &#39;垂直&#39;}`; } }); // 查看单张图片 const viewImage = (index) => { previewMode.value = &#39;单图预览&#39;; if (viewerRef.value && viewerRef.value.$viewer) { viewerRef.value.$viewer.view(index); } }; // 查看所有图片 const viewAll = () => { previewMode.value = &#39;全图集预览&#39;; if (viewerRef.value && viewerRef.value.$viewer) { viewerRef.value.$viewer.show(); } }; // 随机排序图片 const shuffleImages = () => { images.value = [...images.value].sort(() => Math.random() - 0.5); lastAction.value = &#39;随机排序图片&#39;; }; // Viewer初始化回调 const viewerInited = (viewer) => { console.log(&#39;v-viewer 已初始化&#39;); // 添加自定义按钮 viewer.toolbar.appendChild(createDownloadButton(viewer)); }; // 创建下载按钮 const createDownloadButton = (viewer) => { const button = document.createElement(&#39;button&#39;); button.className = &#39;viewer-download&#39;; button.innerHTML = &#39;⬇️&#39;; button.title = &#39;下载图片&#39;; button.style.marginLeft = &#39;10px&#39;; button.style.fontSize = &#39;24px&#39;; button.style.background = &#39;none&#39;; button.style.border = &#39;none&#39;; button.style.cursor = &#39;pointer&#39;; button.style.color = &#39;#fff&#39;; button.addEventListener(&#39;click&#39;, () => { const image = viewer.image; if (image) { const link = document.createElement(&#39;a&#39;); link.href = image.src; link.download = `image-${new Date().getTime()}.jpg`; link.click(); lastAction.value = &#39;下载图片&#39;; } }); return button; }; onMounted(() => { console.log(&#39;图片预览组件已加载&#39;); }); return { images, previewMode, lastAction, previewList, viewerOptions, viewerRef, viewImage, viewAll, shuffleImages, viewerInited }; } }); // 使用v-viewer插件 app.use(VViewer); app.mount(&#39;#app&#39;); </script> </body> </html> ``` ## 代码解释 ### 1. 安装和配置v-viewer 首先需要安装v-viewer库: ```bash npm install v-viewer viewerjs ``` 在Vue3中全局注册: ```javascript import { createApp } from &#39;vue&#39; import App from &#39;./App.vue&#39; import VViewer from &#39;v-viewer&#39; import &#39;viewerjs/dist/viewer.css&#39; const app = createApp(App) app.use(VViewer) app.mount(&#39;#app&#39;) ``` ### 2. 使用v-viewer组件 ```html <viewer :images="previewList" :options="viewerOptions" @inited="viewerInited" ref="viewerRef" > <template #default="scope"> <div v-for="(src, index) in scope.images" :key="index" style="display: none;"> <img :src="src" :data-source="src"> </div> </template> </viewer> ``` - `:images`:绑定要预览的图片列表 - `:options`:配置Viewer.js的选项 - `@inited`:Viewer初始化完成的回调 - `ref`:获取Viewer实例引用 ### 3. Viewer.js配置选项 ```javascript const viewerOptions = reactive({ inline: false, button: true, navbar: true, title: true, toolbar: { zoomIn: 1, zoomOut: 1, oneToOne: 1, reset: 1, prev: 1, play: { show: 1, size: &#39;large&#39; }, next: 1, rotateLeft: 1, rotateRight: 1, flipHorizontal: 1, flipVertical: 1, }, viewed(ev) { // 图片查看事件 }, rotate(ev) { // 图片旋转事件 }, flip(ev) { // 图片翻转事件 } }); ``` ### 4. 图片预览功能实现 **单图预览**: ```javascript const viewImage = (index) => { previewMode.value = &#39;单图预览&#39;; if (viewerRef.value && viewerRef.value.$viewer) { viewerRef.value.$viewer.view(index); } }; ``` **全图集预览**: ```javascript const viewAll = () => { previewMode.value = &#39;全图集预览&#39;; if (viewerRef.value && viewerRef.value.$viewer) { viewerRef.value.$viewer.show(); } }; ``` ### 5. 自定义下载按钮 ```javascript const createDownloadButton = (viewer) => { const button = document.createElement(&#39;button&#39;); // ...按钮样式设置 button.addEventListener(&#39;click&#39;, () => { const image = viewer.image; if (image) { const link = document.createElement(&#39;a&#39;); link.href = image.src; link.download = `image-${new Date().getTime()}.jpg`; link.click(); } }); return button; }; // 在初始化回调中添加按钮 const viewerInited = (viewer) => { viewer.toolbar.appendChild(createDownloadButton(viewer)); }; ``` ## 功能特点 1. **多种预览模式**: - 单图预览:单击图片查看当前图片 - 全图集预览:从第一张开始顺序查看所有图片 2. **丰富的图片操作**: - 缩放(放大、缩小、1:1比例) - 旋转(左右旋转90度) - 翻转(水平和垂直) - 幻灯片播放 - 图片下载 3. **响应式设计**: - 适应不同屏幕尺寸 - 移动设备友好 4. **用户体验优化**: - 图片悬停效果 - 操作记录显示 - 平滑的动画过渡 ## 技术优势 1. **v-viewer特性**: - 基于强大的Viewer.js库 - 支持所有Viewer.js的功能和配置 - 无缝集成到Vue3应用中 2. **Vue3优势**: - 使用Composition API组织代码 - 响应式数据管理 - 组件化开发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值