# # 缩略图

本章节主要介绍了缩略图面板的 UI 结构、布局、标签等内容。 其中涉及到 fragment 的相关操作可以查阅 UI fragments 小节。如果您想了解更多组件相关 API，可查阅 API Reference
(opens new window) 文档。

## # 缩略图面板组件结构说明

在开始实现自定义缩略图 UI 之前， 我们需要先了解这些组件的结构：

1. thumbnail Addon
2. 缩略图面板
3. 缩略图列表

### # thumbnail Addon

在开始使用缩略图组件前，请先确保 `thumbnail` Add 已经正确加载 (可参考 这里)。关于如何加载 Addon 的相关文档，请参考 这里。

### # 缩略图面板

在内置的布局模板中，`<thumbnail-sidebar-panel></thumbnail-sidebar-panel>` 是左侧边栏缩略图面板，它实际上相当于下面的模板：

    <thumbnail:sidebar-panel name="sidebar-thumbnail-panel" @lazy-content="active">
        <thumbnail:toolbar></thumbnail:toolbar>
        <thumbnail:complete-thumbnail-list></thumbnail:complete-thumbnail-list>
    </thumbnail:sidebar-panel>

它包含 `<thumbnail:toolbar>` 和 `<thumbnail:complete-thumbnail-list>` 两个子组件。 如果您想要更改结构，可以参考以下模板：

    <thumbnail:sidebar-panel name="sidebar-thumbnail-panel" @lazy-content="active">
        <thumbnail:complete-thumbnail-list></thumbnail:complete-thumbnail-list>
        <thumbnail:toolbar></thumbnail:toolbar>
    </thumbnail:sidebar-panel>

接下来通过 fragments 配置替换内置的 `sidebar-thumbnail-panel`：

    <script>
        const libPath = window.top.location.origin + '/lib';
        const FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION;
        const pdfui = new UIExtension.PDFUI({
            viewerOptions: {
                libPath: libPath,
                jr: {
                    licenseSN: licenseSN,
                    licenseKey: licenseKey
                }
            },
            renderTo: document.body,
            appearance: UIExtension.appearances.adaptive.extend({
                getDefaultFragments() {
                    return [{
                        target: 'sidebar-thumbnail-panel',
                        action: FRAGMENT_ACTION.REPLACE,
                        template: `
                            <thumbnail:sidebar-panel name="sidebar-thumbnail-panel" @lazy-content="active">
                                <thumbnail:complete-thumbnail-list></thumbnail:complete-thumbnail-list>
                                <thumbnail:toolbar></thumbnail:toolbar>
                            </thumbnail:sidebar-panel>
                        `
                    }]
                }
            }),
            addons: libPath + '/uix-addons/allInOne.js'
        });
    </script>

    {
        "iframeOptions": {
            "style": "height: 500px"
        }
    }

### # 缩略图列表

`<thumbnail:complete-thumbnail-list>` 是一个包含了完整缩略图列表功能的组件，如下所示：

    <thumbnail:thumbnail-list
        @thumbnail:centered
        @thumbnail:rearrange-pages
        @thumbnail:drop-to-merge-doc
        @aria:label="thumbnail:title"
    >
        <thumbnail:thumbnail-item
            @foreach="thumbnail in thumbnail_list.thumbnails track by id"
            @setter.thumbnail_id="thumbnail.id"
            @lazy-content="visible"
        >
            <div class="fv__ui-thumbnail-viewer-container">
                <thumbnail:thumbnail-viewer @setter.thumbnail="thumbnail" @thumbnail:visible-rect-control></thumbnail:thumbnail-viewer>
            </div>
            <div class="fv__ui-thumbnail-item-label">@{thumbnail.pageIndex+1}</div>
        </thumbnail:thumbnail-item>
    </thumbnail:thumbnail-list>

其中涉及的各个结构说明如下：

所在节点 | 结构 | 类型 | 是否必须 | 说明
--- | --- | --- | --- | ---
`<thumbnail:thumbnail-list>` | `@thumbnail:centered` | 指令 | 否 | 用户拖拽侧边栏面板调整面板宽度时，能够控制缩略图列表项正常换行并居中显示
`<thumbnail:thumbnail-list>` | `@thumbnail:rearrange-pages` | 指令 | 否 | 用于支持拖拽缩略图以调整 PDF 页面顺序
`<thumbnail:thumbnail-list>` | `@thumbnail:drop-to-merge-doc` | 指令 | 否 | 用于实现将从外部拖拽到缩略图列表的 PDF 文档插入到指定的位置的功能
`<thumbnail:thumbnail-list>` | `@aria:label="thumbnail:title"` | 指令 | 否 | 无障碍属性
`<thumbnail:thumbnail-item>` | `@foreach="thumbnail in thumbnail_list.thumbnails track by id"` | 指令 | 是 | 这是用于创建缩略图列表的指令，不可修改
`<thumbnail:thumbnail-item>` | `@setter.thumbnail_id="thumbnail.id"` | 指令 | 是 | 缩略图项目必须要的一个指令，用于设置缩略图 id
`<thumbnail:thumbnail-item>` | `@lazy-content="active"` | 指令 | 否 | 用于提升加载缩略图性能
`div.fv__ui-thumbnail-viewer-container` | - | HTML Element | 是 | thumbnail-viewer 容器，不需要做任何调整
`<thumbnail:thumbnail-viewer>` | `@thumbnail:visible-rect-control` | 指令 | 否 | 用于标记和控制 PDF 可见区域
`div.fv__ui-thumbnail-item-label` | - | HTML Element | 否 | 这是一个用于显示当前页缩略信息的容器，我们可以通过修改它来显示更多信息

当您需要自定义缩略图列表时，您需要将 `<thumbnail:complete-thumbnail-list>` 替换为上述模板，如下所示：

    <script>
        const libPath = window.top.location.origin + '/lib';
        const FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION;
        const pdfui = new UIExtension.PDFUI({
            viewerOptions: {
                libPath: libPath,
                jr: {
                    licenseSN: licenseSN,
                    licenseKey: licenseKey
                }
            },
            renderTo: document.body,
            appearance: UIExtension.appearances.adaptive.extend({
                getDefaultFragments() {
                    return [{
                        target: 'sidebar-thumbnail-panel',
                        action: FRAGMENT_ACTION.REPLACE,
                        template: `
                            <thumbnail:sidebar-panel name="sidebar-thumbnail-panel" @lazy-content="active">
                                <thumbnail:toolbar></thumbnail:toolbar>
                                <thumbnail:thumbnail-list
                                    @thumbnail:centered
                                    @thumbnail:rearrange-pages
                                    @thumbnail:drop-to-merge-doc
                                    @aria:label="thumbnail:title"
                                >
                                    <thumbnail:thumbnail-item
                                        @foreach="thumbnail in thumbnail_list.thumbnails track by id"
                                        @setter.thumbnail_id="thumbnail.id"
                                        @lazy-content="visible"
                                    >
                                        <div class="fv__ui-thumbnail-viewer-container">
                                            <thumbnail:thumbnail-viewer @setter.thumbnail="thumbnail" @thumbnail:visible-rect-control></thumbnail:thumbnail-viewer>
                                        </div>
                                        <div class="fv__ui-thumbnail-item-label">@{thumbnail.pageIndex+1}</div>
                                    </thumbnail:thumbnail-item>
                                </thumbnail:thumbnail-list>
                            </thumbnail:sidebar-panel>
                        `
                    }]
                }
            }),
            addons: libPath + '/uix-addons/allInOne.js'
        });
    </script>

    {
        "iframeOptions": {
            "style": "height: 500px"
        }
    }

我们运行上面示例，效果和内置的实现效果相同。

## # 开始自定义缩略图

### # 自定义缩略图项目信息

将 `<div class="fv__ui-thumbnail-item-label">@{thumbnail.pageIndex+1}</div>` 改为 `<div class="fv__ui-thumbnail-item-label">Page: @{thumbnail.pageIndex+1}</div>`， 效果如下：

    <script>
        const libPath = window.top.location.origin + '/lib';
        const FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION;
        const pdfui = new UIExtension.PDFUI({
            viewerOptions: {
                libPath: libPath,
                jr: {
                    licenseSN: licenseSN,
                    licenseKey: licenseKey
                }
            },
            renderTo: document.body,
            appearance: UIExtension.appearances.adaptive.extend({
                getDefaultFragments() {
                    return [{
                        target: 'sidebar-thumbnail-panel',
                        action: FRAGMENT_ACTION.REPLACE,
                        template: `
                            <thumbnail:sidebar-panel name="sidebar-thumbnail-panel" @lazy-content="active">
                                <thumbnail:toolbar></thumbnail:toolbar>
                                <thumbnail:thumbnail-list
                                    @thumbnail:centered
                                    @thumbnail:rearrange-pages
                                    @thumbnail:drop-to-merge-doc
                                    @aria:label="thumbnail:title"
                                >
                                    <thumbnail:thumbnail-item
                                        @foreach="thumbnail in thumbnail_list.thumbnails track by id"
                                        @setter.thumbnail_id="thumbnail.id"
                                        @lazy-content="visible"
                                    >
                                        <div class="fv__ui-thumbnail-viewer-container">
                                            <thumbnail:thumbnail-viewer @setter.thumbnail="thumbnail" @thumbnail:visible-rect-control></thumbnail:thumbnail-viewer>
                                        </div>
                                        <div class="fv__ui-thumbnail-item-label">Page: @{thumbnail.pageIndex+1}</div>
                                    </thumbnail:thumbnail-item>
                                </thumbnail:thumbnail-list>
                            </thumbnail:sidebar-panel>
                        `
                    }]
                }
            }),
            addons: libPath + '/uix-addons/allInOne.js'
        });
    </script>

    {
        "iframeOptions": {
            "style": "height: 500px"
        }
    }

您还可以调整缩略图结构并插入更多组件：

    <script>
        const libPath = window.top.location.origin + '/lib';
        const FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION;
        const pdfui = new UIExtension.PDFUI({
            viewerOptions: {
                libPath: libPath,
                jr: {
                    licenseSN: licenseSN,
                    licenseKey: licenseKey
                }
            },
            renderTo: document.body,
            appearance: UIExtension.appearances.adaptive.extend({
                getDefaultFragments() {
                    return [{
                        target: 'sidebar-thumbnail-panel',
                        action: FRAGMENT_ACTION.REPLACE,
                        template: `
                            <thumbnail:sidebar-panel name="sidebar-thumbnail-panel" @lazy-content="active">
                                <thumbnail:toolbar></thumbnail:toolbar>
                                <thumbnail:thumbnail-list
                                    @thumbnail:centered
                                    @thumbnail:rearrange-pages
                                    @thumbnail:drop-to-merge-doc
                                    @aria:label="thumbnail:title"
                                >
                                    <thumbnail:thumbnail-item
                                        @foreach="thumbnail in thumbnail_list.thumbnails track by id"
                                        @setter.thumbnail_id="thumbnail.id"
                                        @lazy-content="visible"
                                    >
                                        <div class="my-thumbnail-item-toolbox">
                                            <button @controller="thumbnail:DeletePageController">delete</button>
                                            <button @controller="thumbnail:RotateRightController">rotate right</button>
                                            <button @controller="thumbnail:RotateLeftController">rotate left</button>
                                        </div>
                                        <div class="fv__ui-thumbnail-viewer-container">
                                            <thumbnail:thumbnail-viewer @setter.thumbnail="thumbnail" @thumbnail:visible-rect-control></thumbnail:thumbnail-viewer>
                                        </div>
                                    </thumbnail:thumbnail-item>
                                </thumbnail:thumbnail-list>
                            </thumbnail:sidebar-panel>
                        `
                    }]
                }
            }),
            addons: libPath + '/uix-addons/allInOne.js'
        });
    </script>
    <style>
        .my-thumbnail-item-toolbox {
            display: flex;
            padding: 0.2em 0;
            flex-direction: row;
        }
        .my-thumbnail-item-toolbox button{
            height: 2em;
            line-height: 1;
            font-size: 12px;
        }
    </style>

    {
        "iframeOptions": {
            "style": "height: 500px"
        }
    }

### # 自定义缩略图右键菜单

以下是缩略图右键菜单的模板：

    <contextmenu name="fv--thumbnail-contextmenu" @thumbnail:permission>
        <contextmenu-item feature="rotate" name="contextmenu-item-thumbnail-rotate-left" @controller="thumbnail:RotateLeftController">thumbnail:contextmenu.rotateLeft</contextmenu-item>
        <contextmenu-item feature="rotate" name="contextmenu-item-thumbnail-rotate-right" @controller="thumbnail:RotateRightController">thumbnail:contextmenu.rotateRight</contextmenu-item>
        <contextmenu-separator></contextmenu-separator>
        <contextmenu-item feature="insert" name="contextmenu-item-thumbnail-add-blank-page" @controller="thumbnail:InsertBlankPageController">thumbnail:contextmenu.addBlankPage</contextmenu-item>
        <contextmenu-separator></contextmenu-separator>
        <thumbnail:delete-page-contextmenu-item name="contextmenu-item-thumbnail-delete"></thumbnail:delete-page-contextmenu-item>
    </contextmenu>

我们可以通过修改 fragments 配置来删除或添加菜单项：

    <script>
        var libPath = window.top.location.origin + '/lib';
        var FRAGMENT_ACTION = UIExtension.UIConsts.FRAGMENT_ACTION;
        var customModule = UIExtension.modular.module('custom', []);

        customModule.registerController(UIExtension.Controller.extend({
            mounted: function() {
                pdfui.callAddonAPI('Thumbnail','onSelectThumbnail', [function(currentSelectedPageIndexes) {
                    console.log(currentSelectedPageIndexes);
                }]).then(removeListener => {
                    this.addDestroyHook(removeListener);
                })
            }
        }, {
            getName: function() {
                return 'CustomThumbnailItemOperationController';
            }
        }));

        var pdfui = new UIExtension.PDFUI({
            viewerOptions: {
                libPath: libPath,
                jr: {
                    licenseSN: licenseSN,
                    licenseKey: licenseKey
                }
            },
            renderTo: document.body,
            appearance: UIExtension.appearances.adaptive.extend({
                getDefaultFragments() {
                    return [{
                        target: 'contextmenu-item-thumbnail-delete',
                        action: FRAGMENT_ACTION.REMOVE
                    }, {
                        target: 'fv--thumbnail-contextmenu',
                        action: FRAGMENT_ACTION.APPEND,
                        template:`<contextmenu-item @controller="thumbnail:DeletePageController">Custom delete page menu</contextmenu-item>`
                    }, {
                        target: 'fv--thumbnail-contextmenu',
                        action: FRAGMENT_ACTION.APPEND,
                        template: `<contextmenu-item @controller="custom:CustomThumbnailItemOperationController">Custom Action</contextmenu-item>`
                    }]
                }
            }),
            addons: libPath + '/uix-addons/allInOne.js'
        });
    </script>

    {
        "iframeOptions": {
            "style": "height: 500px"
        }
    }