Vue的指令中实现传递更多参数

目录
  • 概要
  • 基本原理
    • 基于闭包的扩展方案
  • 实例和代码实现
    • Main.js中将指令对应的插件全局化
    • ImageLoad插件定义
    • 图片加载管理类的定义
    • Vue 3.0的实现

概要

我们在使用Vue的开发项目中,经常用自定义指令(directive)来封装一系列的DOM操作,这样做非常方便。一般来说,指令是使用动态指令参数来获取App中的数据。

但是有些时候,自定义指令需要更多的数据来完成更复杂的功能,例如在指令中调用当前App实例的nextTick方法,以确保所有DOM元素加载完成,再进行DOM操作。还有一些情况,我们需要将一些全局配置参数传递给指令,已有的参数专递方式,显然无法满足这些需求。

本文介绍一种扩展指令参数的方法,使其可以接收更多参数。该方法在Vue 2.0和 Vue 3.0中,都可以正常使用。

基本原理

本文介绍的指令扩展方法,主要以闭包为基础,并且使用了一些函数参数柯里化的方式来管理多个参数的传递过程。

我们以Vue2.0的指令定义方式为例,说明基本原理。本文所使用的指令定义方式,都已基于插件化的定义方式,在main.js中,通过use方法使用。

示例代码如下:

const myDirective = {
    install(app,options){
        app.directive("img-load", {
            bind:function(el,binding,vnode){ },
            inserted:function(el,binding,vnode){ },
            update:function(el,binding,vnode){ },
            componentUpdated:function(el,binding,vnode){ },
            unbind:function(el,binding,vnode){ },
        });
    }
};
export default myDirective ;

按照上述标准的指令定义方式,无论使用哪个钩子函数,我们只能传递三个参数,指令所绑定的DOM元素,指令接收的APP中绑定参数和虚拟节点。

基于闭包的扩展方案

指令的钩子函数参数已经固定,我们无法修改。但是我们可以通过闭包设置钩子函数的作用域,让闭包函数来接收更多参数。

代码如下:

export default function getMyDirective(Vue) {
    return class MyDirective{
        constructor(options) {
            this.options = options;
            this.bindDirective= this.bindDirective.bind(this);
        }
        bindDirective(el, bindings) {                        
        }
    }
}
const myDirective = {
    install(app,options){
         const DirectiveClass = getMyDirective(app) ;
        var myDirective = new DirectiveClass(options);
        app.directive("my-dirctive", {
            bind:myDirective.bindDirective
        });
    }
};
  • 使用闭包函getMyDirective来包裹钩子函数bindDirective
  • 闭包函数是用户自定义函数,我们可以设置任意多个参数
  • 在闭包函数中定义类来封装指令的所有操作,构造方法也可以接收参数,从而将多个参数柯里化分割。
  • 通过bind方法强行将指令钩子函数绑定的bindDirective方法的this限定为MyDirective的实例,也就是说,bindDirective方法可以通过this访问更多的数据。

JS中函数具有独立作用域,所以指令的绑定方法bindDirective在执行过程中,可以在不受任何外界其他代码的干扰下,使用闭包函数传递的参数。

实例和代码实现

本文以一个图片自动加载的指令为例,介绍自定义指令的参数扩展方式。

自定义指令的基本功能是根据图片的URL地址加载并显示图片,具体实现包括:

  • 通过指令动态参数获取图片地址
  • 首先在页面中显示一个正在加载的图片
  • 加载指定地址图片,如果加载成功,正常显示
  • 加载失败,显示一张加载出错的图片

本文以自顶向下的方式来介绍该实例的代码实现

Main.js中将指令对应的插件全局化

使用use方法,在全局定义插件ImageLoad,该插件主要是功能是在全局定义一个图片加载指令,为该指令接收一个全局配置,即加载中图片地址和加载失败的图片地址。

Vue.use.use(ImageLoad, {
  loading: "http://localhost:4000/images/loading.gif",
  error: "http://localhost:4000/images/error.jpeg",
});

ImageLoad插件定义

ImageLoad插件和其他插件一样,既然要通过use使用,所以要定义install方法,install方法的第一个参数是当前App实例,第二个则是指令的全局配置。

import getImageLoad from './getImageLoad'
const ImageLoad = {
    install(app,options){
        const ImgClass = getImageLoad(app) ;
        var loadImage = new ImgClass(options);
        app.directive("img-load", {
            bind: loadImage.bindImage
        });
    }
};
export default ImageLoad;
  • install方法中,首先通过调用getImageLoad方法,获取加载图片的管理类,传入当前App实例。
  • 实例化图片加载管理类的对象loadImage ,传入图片加载的全局配置。
  • 定义自定义指令v-img-load,该指定的bind钩子方法指向loadImage中的bindImage方法。
  • bindImage方法的this是指向loadImage对象,因此可以使用到App实例,指令全局配置,loadImage对象内的数据。

图片加载管理类的定义

ImageLoadManagement定义了v-img-load指令的全部实现。

export default function getImageLoad(Vue) {
    return class ImageLoadManagement {
        constructor(options) {
            this.options = options;
            this.bindImage = this.bindImage.bind(this);
            this.renderImage = this.renderImage.bind(this);
        }
        bindImage(el, bindings) {
            const self = this;
            Vue.nextTick(function(){
                const src = bindings.value;
                self.renderImage('loading', src, el);
                self.loadImage(src).then(
                    () => self.renderImage('', src, el),
                    () => self.renderImage('error', src, el),
                );
            });
            
        }
        loadImage(src) {
            return new Promise((resolve, reject) => {
                const img = new Image();
                img.src = src;
                img.onload = resolve;
                img.onerror = reject;
            });
        }
        renderImage(type, src, el) {
            let _src;
            const {
                error,
                loading
            } = this.options;
            switch (type) {
                case 'loading':
                    _src = loading;
                    break;
                case 'error':
                    _src = error;
                    break;
                default:
                    _src = src;
                    break;
            }
            el.setAttribute("src", _src);
        }
    }
}

为了避免参数过多,所以采用柯里化的方法,对参数进行了分割:

  • 在闭包函数getImageLoad中,定义了全局App实例参数;
  • ImageLoadManagement 类的构造方法中定义了图片加载指令需要的全局配置参数。
  • class 作为function的语法糖使用,其本质来时function,从而实现独立作用域。
  • bindImage方法中可以直接使用App实例的nextTick,无论该指令在父组件还是子组件中使用,都可以保证在指令中代码执行时,所有DOM元素加载完成。
  • loadImage方法用于检查指定URL的图片是否存在,如果存在则显示具体图片,否则则显示加载失败的图片。
  • renderImage方法用于设置指令绑定的Img元素的图片地址,图片的实际地址可以通过bindings参数的value属性获取。

通过上述方法,我们不仅扩展了指令的参数,使其可以支持更复杂的业务逻辑。

更重要的是。我们实现了指令的定义和实现逻辑的解耦,完全不再需要将所有的指令实现逻辑全部放在指令的注册方法中。通过ImageLoadManagement 的定义,将所有的指令实现逻辑都内聚在其中。

Vue 3.0的实现

Vue 3.0中,指令参数的扩展方法思路与2.0一致,只是因为Vue 3.0中指令的钩子函数名称与2.0不一致,造成一些区别。

具体代码如下:

import getImageLoad from './getImageLoad'
const ImageLoad = {
    install(app,options){
        const ImgClass = getImageLoad(options) ;
        var loadImage = new ImgClass();
        app.directive("img-load", {
            mounted: loadImage.bindImage
        });
    }
};
export default ImageLoad;
export default function getImageLoad(options) {
    return class ImageLoadManagement {
        constructor() {
            this.options = options;
            this.bindImage = this.bindImage.bind(this);
            this.renderImage = this.renderImage.bind(this);
        }
        bindImage(el, bindings) {
            const src = bindings.value;
            this.renderImage('loading', src, el);
            this.loadImage(src).then(
                () => this.renderImage('', src, el),
                () => this.renderImage('error', src, el),
            );
        }
        loadImage(src) {
            return new Promise((resolve, reject) => {
                const img = new Image();
                img.src = src;
                img.onload = resolve;
                img.onerror = reject;
            });
        }
        renderImage(type, src, el) {
            let _src;
            const {
                error,
                loading
            } = this.options;
            switch (type) {
                case 'loading':
                    _src = loading;
                    break;
                case 'error':
                    _src = error;
                    break;
                default:
                    _src = src;
                    break;
            }
            el.setAttribute("src", _src);
        }
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • vue的自定义指令传参方式

    目录 自定义指令传参 指令 环境 传参方式 自定义指令动态参数 自定义指令传参 指令 在vue官网中,常用指令有v-model和v-bind,但是,如果我们需要对DOM元素进行底层操作,就需要用到自定义指令. 今天主要讲到传参的2种方式. 环境 vue2.3.3 node6.11.2 webpack2.6.1 传参方式 在main.js中定义一个指令. Vue.directive('zoom', {     bind: function (el, binding, vnode) {      

  • 八个Vue中常用的v指令详解

    目录 Vue中常用的8种v指令 1 v-text 指令 2 v-html 指令 3 v-on 指令 案例:计数器 4 v-show 指令 5 v-if 指令 6 v-bind 指令 7 v-for 指令 8 v-on 补充 总结 Vue中常用的8种v指令 根据官网的介绍,指令 是带有 v- 前缀的特殊属性.通过指令来操作DOM元素 指令 功能 v-text=“变量/表达式” 文本的设置字符串变量+数字可以直接写是拼接字符串如果出现要使用外部不相同的引号 v-html=“变量” 文本或者页面的设置

  • Vue指令之v-for的使用说明

    目录 Vue v-for的使用 1.迭代普通数组 2.迭代对象数组 3.迭代对象 4.迭代数字 v-for的最佳使用技巧 1.始终在v-for循环中使用key 2.不要在循环中使用v-if 3.使用计算属性或方法来处理数据后再做数据遍历 4.在一个范围内循环 5.在循环中访问项目的索引 6.遍历一个对象 Vue v-for的使用 1.迭代普通数组 在data中定义普通数组 data:{       list:[1,2,3,4,5,6] } 在html中使用 v-for 指令渲染 <p v-for

  • Vue.js自定义指令的基本使用详情

    目录 函数式 对象式 使用时的一些坑 总结 函数式 需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍 <div id="root"> <h2>当前的n值是<span v-text="n"></span></h2> <h2>放大10倍后的n值是:<span v-big="n"></span></h2> <

  • vue指令中的v-once用法

    目录 v-once在日常开发中用的很多 常见用法如下 v-once是什么 v-once在日常开发中用的很多 只渲染元素和组件一次,随后的渲染,使用了此指令的元素/组件及其所有的子节点,都会当作静态内容并跳过,这可以用于优化更新性能. 常见用法如下 当修改input框的值时,使用了v-once指令的p元素不会随之改变,而第二个p元素时可以随之改变的 <div id="app">         <p v-once>{{msg}}</p>  //msg不

  • Vue的指令中实现传递更多参数

    目录 概要 基本原理 基于闭包的扩展方案 实例和代码实现 Main.js中将指令对应的插件全局化 ImageLoad插件定义 图片加载管理类的定义 Vue 3.0的实现 概要 我们在使用Vue的开发项目中,经常用自定义指令(directive)来封装一系列的DOM操作,这样做非常方便.一般来说,指令是使用动态指令参数来获取App中的数据. 但是有些时候,自定义指令需要更多的数据来完成更复杂的功能,例如在指令中调用当前App实例的nextTick方法,以确保所有DOM元素加载完成,再进行DOM操作

  • JSP页面中超链接传递中文参数出现乱码问题解决方法

    本文实例讲述了JSP页面中超链接传递中文参数出现乱码问题解决方法.分享给大家供大家参考,具体如下: 这里分析超链接传递中文参数,在接受页面中出现乱码问题的解决方法. 解决方法: 在接受页面里可以如下处理, 复制代码 代码如下: <%=new String(request.getParameter("变量名字").getBytes("ISO-8859-1")) %> 注意这里用的是 new String() 创建一个新的字符串 例题: 页面一: <h

  • vue项目webpack中Npm传递参数配置不同域名接口

    项目开发中,前端在配置后端api域名时很困扰,常常出现: 本地开发环境: api-dev.demo.com 测试环境: api-test.demo.com 线上生产环境: api.demo.com, 这次是在Vue.js项目中打包,教大家个方法: 使用 npm run build -- xxx   ,根据传递参数xxx来判定不同的环境,给出不同的域名配置. 1.项目中/config/dev.env.js修改: 新增:HOST: '"dev"' 'use strict' const me

  • vue select change事件如何传递自定义参数

    目录 select change事件传递自定义参数 @change函数传自定义参数 实例 select change事件传递自定义参数 今天记录一个小问题,最近get到的一个方法,不太常用,记录一下,增强记忆吧. 之前在vue项目中,也经常使用select标签,也经常用change事件,经常用的change事件中,一直有个默认参数,就是选中的选项的信息,最近一个需求除了需了选中项信息外,还需要其他的参数. 今天记录一下这种传参方式,直接上代码. // 普通用法,没有自定义参数 @change="

  • Vue自定义指令中无法获取this的问题及解决

    目录 自定义指令中无法获取this 解决方法 Vue使用this的这几个坑你都知道吗 一.普通函数 二.Vue中的this 自定义指令中无法获取this 问题 最近在使用自定义指令时遇到一个问题,我想在指令里通过this直接去访问vue实例数据,但是显示未定义,经大佬提醒,里面的this很可能不是指向vue实例 解决方法 在函数里增加第三个参数vnode,vnode.context就是指向当前的vue实例 总结 指令里的this不是指向vue实例,可以使用vnode.context获取this

  • postman中实现传递@RequestBody参数

    目录 传递@RequestBody参数 Java项目中类:(POST请求方法) postman中请求的参数 小结一下 @RequestBody修饰的对象传参数 例如有如下接口 那么在postman中传递参数呢? 传递@RequestBody参数 Java项目中类:(POST请求方法) @PostMapping(value="/fillInfo") public Result<Boolean> fillInfo(@RequestBody RegisterInfoBo info

  • jsp中URL传递中文参数的处理方法

    在页面的url中使用encodeURI(encodeURI(中文)),对中文进行编码,并在服务器的java程序中使用URLDecoder.decode(中文, "UTF-8")进行解码即可; 如果url中需要传递+.#.?等特殊符号,可以使用encodeURIComponent(encodeURIComponent(中文)),服务器解码方法跟encodeURI的解码相同.

  • Spring Boot/VUE中路由传递参数的实现代码

    在路由时传递参数,一般有两种形式,一种是拼接在url地址中,另一种是查询参数.如:http://localhost:8080/router/tang/101?type=spor&num=12.下面根据代码看一下,VUE 和 Spring Boot 中各自是如何处理传递和接受参数的. Spring Boot package com.tang.demo1.controller; import org.springframework.web.bind.annotation.*; @RestContro

  • 关于Python中request发送post请求传递json参数的问题

    昨天遇到了一个奇怪的问题,在Python中需要传递dict参数,利用json.dumps将dict转为json格式用post方法发起请求: params = {"score":{"gt":"80", "lt":"90"}} request.post(url, json.dumps(params)) 但是在服务端接收到的参数日志为: Parameters: {"sno"=>"

  • vue常用指令代码实例总结

    vue常用内置指令 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>12_指令_内置指令</title> <style> [v-cloak] { display: none } </style> </head> <body> <!-- 常用内置指令 v

随机推荐