{"id":15893924,"url":"https://github.com/chinanf-boy/explain-clipboard","last_synced_at":"2026-01-12T06:42:17.645Z","repository":{"id":90548230,"uuid":"114860761","full_name":"chinanf-boy/explain-clipboard","owner":"chinanf-boy","description":"explain --\u003e Clipboard copy or cut in bowser","archived":false,"fork":false,"pushed_at":"2017-12-22T12:29:03.000Z","size":15,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-08T08:47:14.644Z","etag":null,"topics":["clipboard","explain","explain-clipboard"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chinanf-boy.png","metadata":{"files":{"readme":"README.ClipboardAction.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-20T08:10:09.000Z","updated_at":"2017-12-20T08:16:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"9cb9c804-44c6-411a-b039-bca3e3d0d205","html_url":"https://github.com/chinanf-boy/explain-clipboard","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chinanf-boy%2Fexplain-clipboard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chinanf-boy%2Fexplain-clipboard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chinanf-boy%2Fexplain-clipboard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chinanf-boy%2Fexplain-clipboard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chinanf-boy","download_url":"https://codeload.github.com/chinanf-boy/explain-clipboard/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246866100,"owners_count":20846496,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clipboard","explain","explain-clipboard"],"created_at":"2024-10-06T08:14:04.910Z","updated_at":"2026-01-12T06:42:17.611Z","avatar_url":"https://github.com/chinanf-boy.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# ClipboardAction \n\n\u003e 居然找到这里，我行动大魔王把 .btn 抓到这里\n\n\u003e [抢救你的 .btn](#点击事件) `\u003c#######----or----#######\u003e` [返回 Clipboard 类 解释家](./README.md)\n\n---\n\n抢救开始 `explain`\n\n- [配置开始](#配置开始)\n\n- [初始化复制目标](#初始化复制目标)\n\n- [其他](#其他)\n\n    - tiny-emitter\n\n    - execCommand\n\n    - [select库 - 获取元素文本](#选定文本)\n\n- [彩蛋](#类的属性)\n    \n---\n\n点击事件之后\n\n## 配置开始\n\n在 ` Clipboard.js `中\n\n``` js\n        this.clipboardAction = new ClipboardAction({\n            action    : this.action(trigger),\n            target    : this.target(trigger),\n            text      : this.text(trigger),\n            container : this.container,\n            trigger   : trigger,\n            emitter   : this\n        });\n    }\n\n```\n\n### ClipboardAction.js 应用配置\n\n``` js\n    constructor(options) {\n        this.resolveOptions(options); //\u003c--\n        this.initSelection();\n    }\n    resolveOptions(options = {}) {\n    this.action    = options.action; \n    this.container = options.container;\n    this.emitter   = options.emitter;\n    this.target    = options.target;\n    this.text      = options.text;\n    this.trigger   = options.trigger;\n\n    this.selectedText = '';\n}\n```\n\n这个时候要注意啦\n\n`this.action` 的 获得\n\n``` js\n    constructor(options) {\n        // this.action == undefined  --- 0\n        this.resolveOptions(options);\n        // this.action == copy 因为 set   ---- 3\n        this.initSelection(); \n    }\n    resolveOptions(options = {}) {\n        //-- set触发 this.action\n    this.action    = options.action;  // --- 下面的代码块\n        // --- 2  \n    //...\n    }\n```\n\n``` js\n    set action(action = 'copy') { // \u003c--- copy 初始化\n        this._action = action;\n        //   --- 1\n        if (this._action !== 'copy' \u0026\u0026 this._action !== 'cut') {\n            throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n        }\n    }\n\n```   \n\n可以看到, `this.action` -声明的顺序\n\n\u003e再找遍全代码都没有明确声明 \n\n\u003e`this.action 默认 == 'copy'`\n\n\u003e居然用 `set`\n\n[很有想法-讨论](#类的属性) or\n\nnext\n\n---\n\n### 初始化，需要复制的文本\n\n``` js\n    constructor(options) {\n        this.resolveOptions(options); \n        this.initSelection(); //\u003c--\n    }\n    /**\n     * Decides which selection strategy is going to be applied based\n     * on the existence of `text` and `target` properties.\n     */\n    initSelection() {\n        if (this.text) { // 有没有 指定 text\n            // 指定了  Text\n            this.selectFake(); \n        }\n        else if (this.target) { // 有没有指定 目标元素\n            // 指定了  目标元素\n            this.selectTarget();\n        }\n    }\n```\n\nnext\n\n---\n\n## 初始化复制目标\n\n还记得，我们这次的例子吗 `new Clipboard('.btn');`\n\n在本次例子中 target 是存在的 , 当然你也可以看看 selectFake 做了什么\n\n``` html\n\u003c!-- Target --\u003e\n\u003cinput id=\"foo\" value=\"https://github.com/zenorocha/clipboard.js.git\"\u003e\n\n\u003c!-- Trigger --\u003e\n\u003cbutton class=\"btn\" data-clipboard-target=\"#foo\"\u003e\n    \u003cimg src=\"assets/clippy.svg\" alt=\"Copy to clipboard\"\u003e\n\u003c/button\u003e\n```\n\n- [text存在 -\u003e this.selectFake ](#文本存在) \u003c-- 随便逛逛\n\n- [target存在 -\u003e this.selectTarget ](#目标存在) \u003c--本次例子来这里\n\n### 文本存在\n\n``` js\n   /**\n     * Creates a fake textarea element, sets its value from `text` property,\n     * and makes a selection on it.\n     */\n    selectFake() {\n        const isRTL = document.documentElement.getAttribute('dir') == 'rtl';\n\n        this.removeFake(); // \u003c-- 进入先\n\n        ...\n    }\n    /**\n     * Only removes the fake element after another click event, that way\n     * a user can hit `Ctrl+C` to copy because selection still exists.\n     */\n    removeFake() { // 看来是移除 fake 事件和 元素\n        if (this.fakeHandler) {\n            this.container.removeEventListener('click', this.fakeHandlerCallback);\n            this.fakeHandler = null;\n            this.fakeHandlerCallback = null;\n        }\n\n        if (this.fakeElem) {\n            this.container.removeChild(this.fakeElem);\n            this.fakeElem = null;\n        }\n    }\n```\n\nnext\n\n``` js\n   selectFake() {\n        const isRTL = document.documentElement.getAttribute('dir') == 'rtl'; // ？\n\n        this.removeFake();\n        \n        // 接下来\n        this.fakeHandlerCallback = () =\u003e this.removeFake();\n\n        // this.container == document.body\n        this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;\n\n        // 创建一个 textarea 空元素\n        this.fakeElem = document.createElement('textarea');\n        // Prevent zooming on iOS \n        this.fakeElem.style.fontSize = '12pt';\n        // Reset box model\n        this.fakeElem.style.border = '0';\n        this.fakeElem.style.padding = '0';\n        this.fakeElem.style.margin = '0';\n        // Move element out of screen horizontally\n        this.fakeElem.style.position = 'absolute';\n        this.fakeElem.style[ isRTL ? 'right' : 'left' ] = '-9999px';\n        // Move element to the same position vertically\n        let yPosition = window.pageYOffset || document.documentElement.scrollTop;\n        this.fakeElem.style.top = `${yPosition}px`;\n\n        this.fakeElem.setAttribute('readonly', '');\n        this.fakeElem.value = this.text;\n\n        //______********_______*********\n\n        // this.fakeElem\n        // \u003ctextarea style=\"font-size:12pt;border:0;padding:0;margin:0;position:'absolute';left:'-9999px';top:***\"\u003e\n        // this.text is nothing\n        //\u003c/textarea\u003e\n\n    //top: *** 表示滚动网页离最上面的距离\n    // 所以其实，本次例子，没有进到 selectFake,因为有 target\n\n        this.container.appendChild(this.fakeElem);\n\n        this.selectedText = select(this.fakeElem); //？\n        this.copyText();\n    }\n```\n\n``` js\n    /**\n     * Only removes the fake element after another click event, that way\n     * a user can hit `Ctrl+C` to copy because selection still exists.\n     */\n    removeFake() {\n        if (this.fakeHandler) {\n            // 全局 事件 remove\n            this.container.removeEventListener('click', this.fakeHandlerCallback);\n            this.fakeHandler = null;\n            this.fakeHandlerCallback = null;\n        }\n\n        if (this.fakeElem) { // 创建的 元素 \n        //remove\n            this.container.removeChild(this.fakeElem);\n            this.fakeElem = null;\n        }\n    }\n```\n\n---\n\n### 目标存在\n\n``` js\n    /**\n     * Selects the content from element passed on `target` property.\n     */\n    // 真的短，额不是我是说，真简洁\n    selectTarget() {\n        this.selectedText = select(this.target); //\n        this.copyText();\n    }\n```\n\n看来我们需要，[弄清楚 select库 的能力了--点击](#选定文本)\n\n不过初步看应该是对元素 `element`的 `value` 进行选定\n\nnext\n\n---\n\n复制文本\n\n`this.copyText`\n\n``` js\n    /**\n     * Executes the copy operation based on the current selection.\n     */\n    copyText() {\n        let succeeded;\n\n        try {\n            // this.action 默认 copy \n            succeeded = document.execCommand(this.action);\n\n            // 详细 execCommand 在 其他便签\n        }\n        catch (err) {\n            succeeded = false;\n        }\n        // succeeded == false\n        this.handleResult(succeeded);\n    }\n        /**\n     * Fires an event based on the copy operation result.\n     * @param {Boolean} succeeded\n     */\n    handleResult(succeeded) {\n        // this.emitter \n        // Emitter.emit 类  \n        // 触发一个命名的事件\n        // succeeded == false\n        \n        this.emitter.emit(succeeded ? 'success' : 'error', {\n            action: this.action,\n            text: this.selectedText,\n            trigger: this.trigger,\n            clearSelection: this.clearSelection.bind(this)\n        });\n    }\n```\n\n[传递 `删除函数 destroy`](./README.md#L321)\n\nor [源码--](./clipboard.js-master/src/clipboard.js#111)\n\n``` js\n    /**\n     * Destroy lifecycle.\n     */\n    destroy() {\n        this.removeFake();\n    }\n```\n\n## 其他\n\n- [tiny-emitter 小于1](#https://github.com/scottcorgan/tiny-emitter)\n\n- [document.execCommand- 命令](https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand)\n\n### 选定文本\n\nselect 库\n\n``` js\nimport select from 'select';\n```\n[https://github.com/zenorocha/select](#https://github.com/zenorocha/select)\n\n## 类的属性\n\n使用 `set` 初始化 变量\n\n示例\n\n[http://jsbin.com/jogewib/edit?js,console](http://jsbin.com/jogewib/edit?js,console)\n\n除了 `action` , 还有 `target`\n\n``` js\n    /**\n     * Sets the `target` property using an element\n     * that will be have its content copied.\n     * @param {Element} target\n     */\n    set target(target) {\n        if (target !== undefined) {\n            if (target \u0026\u0026 typeof target === 'object' \u0026\u0026 target.nodeType === 1) {\n                if (this.action === 'copy' \u0026\u0026 target.hasAttribute('disabled')) {\n                    throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n                }\n\n                if (this.action === 'cut' \u0026\u0026 (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n                    throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n                }\n\n                this._target = target;\n            }\n            else {\n                throw new Error('Invalid \"target\" value, use a valid Element');\n            }\n        }\n    }\n\n        /**\n     * Gets the `target` property.\n     * @return {String|HTMLElement}\n     */\n    get target() {\n        return this._target;\n    }\n```\n\n对于 Clipboard 作者来说\n\n `set`的作用似乎是`初始化变量`，以及 对 `变量的错误处理`","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchinanf-boy%2Fexplain-clipboard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchinanf-boy%2Fexplain-clipboard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchinanf-boy%2Fexplain-clipboard/lists"}