撬墙角是什么意思| 妍什么意思| 天蝎座和什么星座配| 葛根粉吃了有什么好处| 胆道闭锁有什么症状| 合肥以前叫什么| 二是什么意思| 什么病不能吃玉米| 派出所什么时候上班| 经常饿肚子会导致什么后果| 糖尿病人吃什么水果最好| 简单明了是什么意思| 冰箱什么品牌好| 什么的月光| 中性粒细胞比率偏低是什么意思| 多巴胺分泌是什么意思| 办理身份证需要带什么| 百日咳是什么| 锖色是什么颜色| 算命先生是什么生肖| 神经官能症挂什么科| 外痔长什么样| 口红什么牌子最好| 饭后腹胀是什么原因| wba是什么意思| dr检查是什么意思| 沉香手串有什么好处| 数词是什么意思| 胃溃疡吃什么水果好| 什么的头发| 佯装是什么意思| fujixerox是什么牌子| 大小眼是什么原因| 什么是自闭症| 跟腱断裂是什么感觉| 缺钠是什么原因造成的| 肝胃不和吃什么药| 大三阳是什么病| 宾馆和酒店有什么区别| 201是什么意思| 向日葵什么时候播种| rush什么意思| 紫色是什么颜色调出来的| 肚脐上方是什么器官| 气是什么生肖| 什么是御姐| 耳朵后面疼是什么原因| 什么含胶原蛋白最多| 车票改签是什么意思| 灰色五行属什么| 开方是什么意思| 一什么三什么的成语| 双数是什么| 肾病什么症状| 唇周围长痘痘是什么原因| 今天是什么节日吗| 葡萄糖偏高是什么意思| 精液是什么形成的| 智齿发炎肿痛吃什么药| 肚子不舒服吃什么药| 梦到生儿子有什么预兆| 头晕四肢无力是什么原因| 什么叫不动产| 小孩口腔溃疡是什么原因引起的| 理数是什么| hpf是什么意思| 缓刑是什么意思| 淋巴细胞偏高说明什么问题| 心脏右束支传导阻滞是什么意思| PT医学上是什么意思| 为什么容易中暑| 什么的白塔| 本田的高端品牌是什么| 交叉感染是什么意思| 白酒优级和一级有什么区别| 湘潭市花是什么| 热痱子是什么样子图片| 安溪铁观音属于什么茶| 膝盖咔咔响是什么原因| 主人杯是什么意思| 为什么会尿酸高| mm代表什么| 什么是痤疮图片| 什么是糖尿病| 头疼头晕是什么原因| 什么是免疫组化检查| 逍遥丸的功效和作用是什么| 亚硝酸钠是什么| 拐子是什么意思| 硬伤是什么意思| 熬夜对肾有什么影响| 高血压什么意思| 天干指的是什么| 桑叶有什么功效| 菊花是什么颜色| 化脓性扁桃体炎吃什么药| 腰肌劳损贴什么膏药| 血竭是什么东西| 恚是什么意思| 父母坟上长树意味什么| 龙骨为什么比排骨便宜| 喉咙发炎吃什么药最好| 蓓蕾是什么意思| 梦见红棺材是什么征兆| 孕妇什么时候有奶水| 牛肉不能和什么食物一起吃| 七月一号什么星座| 吃韭菜有什么好处| 眼睛总是干涩是什么原因| 产后第一次来月经是什么颜色| 经常吃紧急避孕药有什么危害| 贡菊泡水喝有什么功效| 悦是什么意思| 什么情况下需要根管治疗| 脑供血不足什么症状| 妃子是什么意思| 小候鸟是什么意思| 上水是什么意思| 收口是什么意思| 欧芹在中国叫什么| 低压高有什么危险| 黄体破裂有什么症状| 生命的真谛是什么| sp什么意思| 姨妈量少是什么原因| 品种是什么意思| 舌头臭是什么原因| 吃什么最补胶原蛋白| 孙子兵法到底说什么| 威慑力是什么意思| 外耳炎用什么药| 子宫内膜薄吃什么药| 罄竹难书什么意思| 田亮为什么不娶郭晶晶| 生冷辛辣指的是什么| 感冒吃什么好得快| 下面痛是什么原因| 生理期吃什么比较好| 裸睡有什么好处| 江西景德镇有什么好玩的地方| 鸡肉与什么食物相克| 属狗的和什么属相最配| 蛋白质阳性什么意思| 炸鱼是什么意思| 人乳头瘤病毒阴性是什么意思| 9月9日什么星座| 喝红酒有什么好处| 丼什么意思| 马与什么属相相克相冲| 儿童乳房发育挂什么科| 纹身纹什么招财好运| 投桃报李是什么生肖| 家里飞蛾多是什么原因| 农历六月初十是什么日子| 瞿读什么| 追逐是什么意思| 宰相肚里能撑船是什么意思| 什么人适合吃蛋白质粉| 美缝剂什么牌子的好| 227什么意思| 年轻人白头发是什么原因引起的| 家里停电了打什么电话| 刮脸有什么好处与坏处| 手机电池是什么电池| 钾低吃什么| 太阳一晒脸就红是什么原因| 做小月子要注意什么| 4.26是什么星座| 长期口苦是什么原因| 榴莲和什么食物相克| 小确幸什么意思| 维生素b12治什么病| 绒毛膜促性腺激素是什么意思| 尿路感染检查什么项目| leep术是什么手术| 此刻朋友这杯酒最珍贵是什么歌| 有氧运动是什么意思| 桃子是什么季节的水果| 老人喝什么牛奶好| 乳头为什么会痛| 什么样人不能吃海参| 中央党校校长是什么级别| 什么运动有助于长高| 犹太人为什么那么聪明| 发烧输液输的是什么药| 寒食节是什么意思| 以梦为马是什么意思| sakura是什么牌子| 锁阳是什么东西| 背靠背协议是什么意思| 女性尿酸低是什么原因| 小孩不吃饭是什么原因| 芹菜和什么菜搭配最好| 为什么叫北洋政府| 切除胆囊有什么影响| 铁蛋白高挂什么科| 海米是什么| 盔甲是什么意思| 纳是什么意思| 头上汗多是什么原因| 病毒性扁桃体炎吃什么药| 情何以堪是什么意思| 小孩晚上磨牙是什么原因引起的| 什么东西补血最快| 品检是做什么的| 非分之想什么意思| 猫薄荷对猫有什么作用| 间接胆红素偏高什么意思| 小狗能看见什么颜色| 什么因果才会有双胞胎| 四月28日是什么星座| 大便干燥一粒一粒的吃什么药| 甲状腺弥漫性病变是什么意思| 原发性高血压什么意思| 简单明了是什么意思| 抗生素药对人体有什么危害| 心率低有什么症状| 什么是内分泌失调| 黄昏是什么时候| 水蛭是什么动物| 胰腺炎挂什么科室| 用什么药膏能拔去粉瘤| 梦见很多蜘蛛是什么意思| barbour是什么牌子| 皮蛋是什么蛋做的| 麦芽糊精是什么| 吃什么补眼睛| 真命题是什么意思| 1980年属什么| 憋屎会造成什么后果| 双排是什么意思| 偏头痛什么原因引起| 胆结石用什么药| 骨相美是什么意思| 空调变频和定频有什么区别| 人中深的女人代表什么| 9月28号是什么星座| 淋巴滤泡增生吃什么药| 肾结石发作有什么症状| 有尿意但是尿不出来是什么原因| 摩纳哥为什么这么富| 5月29日什么星座| 水泡长什么样| 肝火旺盛吃什么食物| 7月1日是什么节日| hip是什么意思| 泮是什么意思| 了加一笔是什么字| 跑步胸口疼什么原因| 北京的市花是什么花| 4月27日是什么星座| 梦见收稻谷有什么预兆| 一片冰心在玉壶的冰心是什么意思| 舌头有点麻是什么病的前兆| 口干舌燥吃点什么药| 蔡英文是什么党派| rem是什么意思| 清道夫鱼有什么作用| 莫欺少年穷是什么意思| 为什么不开朱元璋的墓| nag是什么意思| 无氧运动是什么| 肺气虚吃什么中成药| 腰部酸胀是什么原因| 百度
Skip to content

面试官:你有写过自定义指令吗?自定义指令的应用场景有哪些??#21

@febobo

Description

@febobo

一、什么是指令

开始之前我们先学习一下指令系统这个词

指令系统是计算机硬件的语言系统,也叫机器语言,它是系统程序员看到的计算机的主要属性。因此指令系统表征了计算机的基本功能决定了机器所要求的能力

vue中提供了一套为数据驱动视图更为方便的操作,这些操作被称为指令系统

我们看到的v- 开头的行内属性,都是指令,不同的指令可以完成或实现不同的功能

除了核心功能默认内置的指令 (v-modelv-show),Vue 也允许注册自定义指令

指令使用的几种方式:

//会实例化一个指令,但这个指令没有参数 
`v-xxx`

// -- 将值传到指令中
`v-xxx="value"`  

// -- 将字符串传入到指令中,如`v-html="'<p>内容</p>'"`
`v-xxx="'string'"` 

// -- 传参数(`arg`),如`v-bind:class="className"`
`v-xxx:arg="value"` 

// -- 使用修饰符(`modifier`)
`v-xxx:arg.modifier="value"` 

二、如何实现

注册一个自定义指令有全局注册与局部注册

全局注册注册主要是用过Vue.directive方法进行注册

Vue.directive第一个参数是指令的名字(不需要写上v-前缀),第二个参数可以是对象数据,也可以是一个指令函数

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()  // 页面加载完成之后自动让输入框获取到焦点的小功能
  }
})

局部注册通过在组件options选项中设置directive属性

directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus() // 页面加载完成之后自动让输入框获取到焦点的小功能
    }
  }
}

然后你可以在模板中任何元素上使用新的 v-focus property,如下:

<input v-focus />

自定义指令也像组件那样存在钩子函数:

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用

  • unbind:只调用一次,指令与元素解绑时调用

所有的钩子函数的参数都有以下:

  • el:指令所绑定的元素,可以用来直接操作 DOM
  • binding:一个对象,包含以下 property
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnodeVue 编译生成的虚拟节点
  • oldVnode:上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用

除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行

举个例子:

<div v-demo="{ color: 'white', text: 'hello!' }"></div>
<script>
    Vue.directive('demo', function (el, binding) {
    console.log(binding.value.color) // "white"
    console.log(binding.value.text)  // "hello!"
    })
</script>

三、应用场景

使用自定义组件组件可以满足我们日常一些场景,这里给出几个自定义组件的案例:

  • 防抖
  • 图片懒加载
  • 一键 Copy的功能

输入框防抖

防抖这种情况设置一个v-throttle自定义指令来实现

举个例子:

// 1.设置v-throttle自定义指令
Vue.directive('throttle', {
  bind: (el, binding) => {
    let throttleTime = binding.value; // 防抖时间
    if (!throttleTime) { // 用户若不设置防抖时间,则默认2s
      throttleTime = 2000;
    }
    let cbFun;
    el.addEventListener('click', event => {
      if (!cbFun) { // 第一次执行
        cbFun = setTimeout(() => {
          cbFun = null;
        }, throttleTime);
      } else {
        event && event.stopImmediatePropagation();
      }
    }, true);
  },
});
// 2.为button标签设置v-throttle自定义指令
<button @click="sayHello" v-throttle>提交</button>

图片懒加载

设置一个v-lazy自定义组件完成图片懒加载

const LazyLoad = {
    // install方法
    install(Vue,options){
    	  // 代替图片的loading图
        let defaultSrc = options.default;
        Vue.directive('lazy',{
            bind(el,binding){
                LazyLoad.init(el,binding.value,defaultSrc);
            },
            inserted(el){
                // 兼容处理
                if('IntersectionObserver' in window){
                    LazyLoad.observe(el);
                }else{
                    LazyLoad.listenerScroll(el);
                }
                
            },
        })
    },
    // 初始化
    init(el,val,def){
        // data-src 储存真实src
        el.setAttribute('data-src',val);
        // 设置src为loading图
        el.setAttribute('src',def);
    },
    // 利用IntersectionObserver监听el
    observe(el){
        let io = new IntersectionObserver(entries => {
            let realSrc = el.dataset.src;
            if(entries[0].isIntersecting){
                if(realSrc){
                    el.src = realSrc;
                    el.removeAttribute('data-src');
                }
            }
        });
        io.observe(el);
    },
    // 监听scroll事件
    listenerScroll(el){
        let handler = LazyLoad.throttle(LazyLoad.load,300);
        LazyLoad.load(el);
        window.addEventListener('scroll',() => {
            handler(el);
        });
    },
    // 加载真实图片
    load(el){
        let windowHeight = document.documentElement.clientHeight
        let elTop = el.getBoundingClientRect().top;
        let elBtm = el.getBoundingClientRect().bottom;
        let realSrc = el.dataset.src;
        if(elTop - windowHeight<0&&elBtm > 0){
            if(realSrc){
                el.src = realSrc;
                el.removeAttribute('data-src');
            }
        }
    },
    // 节流
    throttle(fn,delay){
        let timer; 
        let prevTime;
        return function(...args){
            let currTime = Date.now();
            let context = this;
            if(!prevTime) prevTime = currTime;
            clearTimeout(timer);
            
            if(currTime - prevTime > delay){
                prevTime = currTime;
                fn.apply(context,args);
                clearTimeout(timer);
                return;
            }

            timer = setTimeout(function(){
                prevTime = Date.now();
                timer = null;
                fn.apply(context,args);
            },delay);
        }
    }

}
export default LazyLoad;

一键 Copy的功能

import { Message } from 'ant-design-vue';

const vCopy = { //
  /*
    bind 钩子函数,第一次绑定时调用,可以在这里做初始化设置
    el: 作用的 dom 对象
    value: 传给指令的值,也就是我们要 copy 的值
  */
  bind(el, { value }) {
    el.$value = value; // 用一个全局属性来存传进来的值,因为这个值在别的钩子函数里还会用到
    el.handler = () => {
      if (!el.$value) {
      // 值为空的时候,给出提示,我这里的提示是用的 ant-design-vue 的提示,你们随意
        Message.warning('无复制内容');
        return;
      }
      // 动态创建 textarea 标签
      const textarea = document.createElement('textarea');
      // 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
      textarea.readOnly = 'readonly';
      textarea.style.position = 'absolute';
      textarea.style.left = '-9999px';
      // 将要 copy 的值赋给 textarea 标签的 value 属性
      textarea.value = el.$value;
      // 将 textarea 插入到 body 中
      document.body.appendChild(textarea);
      // 选中值并复制
      textarea.select();
      // textarea.setSelectionRange(0, textarea.value.length);
      const result = document.execCommand('Copy');
      if (result) {
        Message.success('复制成功');
      }
      document.body.removeChild(textarea);
    };
    // 绑定点击事件,就是所谓的一键 copy 啦
    el.addEventListener('click', el.handler);
  },
  // 当传进来的值更新的时候触发
  componentUpdated(el, { value }) {
    el.$value = value;
  },
  // 指令与元素解绑的时候,移除事件绑定
  unbind(el) {
    el.removeEventListener('click', el.handler);
  },
};

export default vCopy;

关于自定义组件还有很多应用场景,如:拖拽指令、页面水印、权限校验等等应用场景

参考文献

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      塔利班是什么 子宫为什么会长息肉 蒲公英有什么作用和功效 木薯粉是什么东西 邮政编码有什么用
      什么是1型和2型糖尿病 吃什么对牙齿有好处 肝阳上亢是什么意思 办理慢性病需要什么手续 扁桃体发炎看什么科
      男人吃什么补身体 摩什么擦什么 女人能日到什么时候 肺气不足有什么症状 希鲮鱼是什么鱼
      给孩子测骨龄应该挂什么科 bm是什么意思 脉搏90左右意味着什么 白带豆腐渣用什么药 低血糖是什么引起的
      热气是什么意思shenchushe.com 梦见好多死人是什么征兆hcv7jop4ns7r.cn 什么面什么刀hcv9jop4ns5r.cn 什么是先兆流产hcv8jop8ns9r.cn 变异是什么意思hcv7jop4ns6r.cn
      血气方刚什么意思hcv7jop9ns4r.cn 拍黄瓜是什么意思hcv9jop7ns4r.cn 八月十日是什么星座hcv9jop2ns8r.cn 巴戟天为什么要抽芯hcv8jop7ns4r.cn 护理学是干什么的hcv8jop1ns3r.cn
      supra是什么牌子hcv8jop7ns7r.cn 什么是集成灶hcv8jop8ns1r.cn 备孕叶酸什么时候吃最好hcv8jop9ns2r.cn europe是什么意思chuanglingweilai.com 虎毒不食子是什么意思hcv8jop2ns9r.cn
      亲子鉴定需要什么材料zhongyiyatai.com 陈赫为什么离婚hcv9jop8ns2r.cn 每逢佳节倍思亲的上一句是什么liaochangning.com 梦见鳄鱼是什么意思hcv9jop5ns2r.cn 臭粉是什么东西gysmod.com
      百度