Vue:Vue.directive、Vue.filter、this.$set、this.$forceUpdate的使用详解

Vue.directive

官方原话

在 Vue2.0 中,代码复用和抽象的主要形式是组件。
然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令

1、概括

1.1 语法:全局注册

// id:自定义指令的名称,
// [definition]:钩子函数
  Vue.directive(id,[definition])

demo示例

// main.js
// 全局注册
Vue.directive('focus',{
  // 当绑定元素插入到 DOM 中
  inserted: function(el) {
    el.focus();
  }
})
new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app')
// 页面引入
<template>
  <div class="content">
    <input type="text" v-focus/>
  </div>
</template> 

1.2 钩子函数

一个指令定义对象可以提供如下几个钩子函数(均为可选):

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  • unbind:只调用一次,指令与元素解绑时调用。
// 注册
Vue.directive('my-directive',{
    bind:  function () {},         
    inserted: function () {},
    update: function () {},
    componentUpdated: function () {},
    unbind: function() {}
})

1.3 钩子函数的参数

指令钩子函数会被传入以下参数:

  • 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 }
  • vnode:Vue 编译生成的虚拟节点。
  • oldVnode:上一个虚拟节点,仅在updatecomponentUpdated钩子中可用。

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

(1) demo示例
<template>
  <div class="content">
    <div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
  </div>
</template>  

<script>
export default {
  name: 'Content',
  data(){
    return{
      message: 'hello!'
    }
  },
  directives: {
    demo:{
      bind: function (el, binding, vnode) {
        var s = JSON.stringify
        el.innerHTML =
        'name: '       + s(binding.name) + '<br>' +
        'value: '      + s(binding.value) + '<br>' +
        'expression: ' + s(binding.expression) + '<br>' +
        'argument: '   + s(binding.arg) + '<br>' +
        'modifiers: '  + s(binding.modifiers) + '<br>' +
        'vnode keys: ' + Object.keys(vnode).join(', ')
      }
    }
  }
}
</script>
(2) 页面显示

在这里插入图片描述

1.4 函数简写

在很多时候,你可能想在bindupdate时触发相同行为,而不关心其它的钩子。比如这样写:

Vue.directive('color-swatch', function (el, binding) {
  el.style.backgroundColor = binding.value
})

2、常用案例

2.1 输入框聚焦

2.2 绑定背景颜色

2.3 文字显示

<template>
    <div>
        <div id="app"><input v-focus /></div>
        <hr>
        <p style="width:200px;height:200px" v-pin='colors'>trying</p> 
        <hr>
        <div id="app" v-demo:foo.a.b="message"></div>
    </div>
</template>
<script>
import Vue from "vue"; 
 
// 1、输入框聚焦
Vue.directive("focus", {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus();
  },
});
 
// 2、绑定背景颜色
Vue.directive('pin', function(el, binding) { //背景颜色
    el.style.background = binding.value
})
 
// 3、文字显示
Vue.directive('demo', {
  bind: function (el, binding, vnode) {
    var s = JSON.stringify
    el.innerHTML =
      'name: '       + s(binding.name) + '<br>' +
      'value: '      + s(binding.value) + '<br>' +
      'expression: ' + s(binding.expression) + '<br>' +
      'argument: '   + s(binding.arg) + '<br>' +
      'modifiers: '  + s(binding.modifiers) + '<br>' +
      'vnode keys: ' + Object.keys(vnode).join(', ')
  }
})
 
 
export default {
    name: "directive",
    data() {
        return {
            colors:"",//定义变量接收
            message:'left',
        }
    },
    created(){
        this.colors="pink"
    }
}
</script>

2.4 使用vue.directive的图片加载

<template>
  <div>
    <div v-img="url" style="width: 500px; height: 500px;"></div>
  </div>
</template>
<script>
import Vue from "vue"; //需要引入
Vue.directive("img", {
    bind:function(el){    
    var color = Math.floor(Math.random() * 1000000);
    el.style.backgroundColor = "#" + color;
    },
  inserted: function (el, binding) {
    var img = new Image();
    img.src = binding.value;
    img.onload = function () {
      el.style.backgroundImage = "url(" + binding.value + ")";
    };
  },
});
 
export default {
  name: "directive",
  data() {
    return {
      url: "../../../1.jpg",//据具体图片存储文件夹而定
 
    };
  },
};
</script>

2.5 自定义指令实现拖拽

// 全局自定义指令(必须在实例之前)
/*
参数1:指令的名称
参数2:指令实现的函数
*/
Vue.directive('drag', (el, { value, modifiers }) => {
  // el代表使用该指令的元素
  el.onmousedown = function (e) {
    // console.log("s");
    var disx = e.offsetX
    var disy = e.offsetY
    // 阻止浏览器的默认事件
    e.preventDefault()
    document.onmousemove = function (e) {
      var x = e.clientX - disx
      var y = e.clientY - disy
      // 如果表达式的结果是false,就不拖拽
      if (!value) {
        return
      }
      // 修饰符
      if (modifiers.x) {
        el.style.left = x + 'px'
      }
      // 修饰符
      if (modifiers.y) {
        el.style.top = y + 'px'
      }
      if (!(modifiers.x && !modifiers.y) && value) {
        el.style.left = x + 'px'
        el.style.top = y + 'px'
      }
    }
    document.onmouseup = function () {
      document.onmousemove = null
      document.onmouseup = null
    }
  }
})
<template>
  <div id="app">
    <!-- //y轴拖拽: 全拖拽,不是y轴 -->
    <div class="box" v-drag.y="show">y</div>
    <!-- //x轴拖拽 -->
    <div class="box" v-drag.x="show">x</div>
  </div>
</template>

<script>
export default {
  name: 'directive',
  data () {
    return {
      show: true
    }
  }

}
</script>

<style scoped>
.box {
  width: 100px;
  height: 100px;
  background: red;
  position: absolute;
}
</style>

Vue.filter

官方原话

Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。
过滤器分:全局过滤器和局部过滤器,重点说下全局过滤器,因为全局过滤器在项目中使用频率非常高!

1、概括

1.1 语法:全局注册

// 第一个参数:是过滤器的ID(即名字),
// 第二个参数:一个处理函数,过滤器要实现的功能在这个函数中定义。
Vue.filter('capitalize', function (value) {
     if (!value) return ''
     value = value.toString()
     return value.toUpperCase();
})

1.2 语法:使用过滤器

<div>{{ message | capitalize }}</div>

1.3 demo示例


<div id="app">
    <input type="text" v-model="message">
    {{ message | capitalize }}
</div>
<script>
     Vue.filter('capitalize', function (value) {
          if (!value) return ''
          value = value.toString()
          return value.toUpperCase();
     })
     new Vue({
         el:'#app',
         data:{
           message:'java'
         }
     })
</script>

2、实际开发场景

在实际开发中,全局过滤器经常会被在数据(比如时间、日期的装饰)上边,通常我们会把处理函数给抽离出去,统一放在一个.js文件中,下边用代码说下.

//filter.js 文件
 
let filter_price = function (val,...params){
    return "¥" + val
}
let filter_date = function (){
    return "2019/10/20" + val
}
export {filter_price,filter_date} //导出过滤函数

2.1 main.js循环注册过滤器

//main.js
 
//下边是2种导入方式,推荐第一种
import * as _filter from './filters/filter'
// import {filter_price,filter_date} from './filters/filter'
 
console.log(_filter)
 
Object.keys(_filter).forEach(item=>{
  Vue.filter(item,_filter[item])
})
 
new Vue({
  router,store,
  render: h => h(App),
}).$mount('#app')

2.2 在vue文件中使用过滤器

<template>
    <div>
      <h1>{{price | filter_price}}</h1>
    </div>
</template>
 
<script>
export default {
    name:'news',
    data(){
        return{
            price:1200
        }
    }  
}
</script>

Vue.filter:
模板中 文本后边需要添加管道符号( | )作为分隔,
管道符 | 后边是文本的处理函数,

  • 处理函数的第一个参数是:管道符前边的——文本内容
  • 如果处理函数还需要传递其他参数,则从第二个参数依次往后是传递的参数

this.$set

官方原话

向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。
它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = ‘hi’)
简单理解:就是添加/修改一个响应式对象属性的。

语法:this.$set(数组/对象,索引,新值)

1、基本使用

<template>
  <div>
    <ul>
      <li v-for="item in arr">{{ item }}</li>
    </ul>
    <button @click="soBtn">排序</button>
    <button @click="reBtn">翻转</button>
    <button @click="jBtn">截取前3个</button>
    <button @click="upBtn">点击改掉第一个元素的值</button>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      arr: [3, 15, 10, 1, 19, 32],
    };
  },
  methods: {
    soBtn() {
      this.arr.sort();
    },
    reBtn() {
      this.arr.reverse();
    },
    jBtn() {
      this.arr = this.arr.slice(0, 3);
    },
    upBtn() {
      // this.arr[0] = "老李"; // 页面无变化 - vue无法监测数组里值的改变
      // 可以使用数组提供的方法
      // 数据目标, 索引, 新值
      // Vue.set(this.arr, 0, "老李"); // 静态方法set
      this.$set(this.arr, 0, "老李"); // 实例方法$set
    },
  },
};
</script>

this.$forceUpdate

官方原话

迫使 Vue 实例重新渲染。
注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
简单理解:数据没有响应式更新时,也可以通过this.$forceUpdate()强制刷新


<template>
  <div>
    <p>{{ userInfo.name }}</p>
    <button @click="updateName">修改userInfo</button>
  </div>
</template>

<script>
export default {
  data () {
    return {
      userInfo: { name: '小明' }
    }
  },
  methods: {
    updateName () {
      this.userInfo.name = '小红'
    }
  }
}
</script>

<style scoped>
</style>

updateName函数中,我们尝试给userInfo对象修改值,发现页面其实并没有变化.

那这时候有两种解决方法:

方法一:

methods:{
  updateName(){
    this.userInfo.name='小红'//在此时,确实已经将userInfo对象修改完成
    console.log(this.userInfo.name);//输出结果: 小红
    this.$forceUpdate();//在这里,强制刷新之后,页面的结果变为'小红'
  }
}

方法二:

methods:{
  updateName(){
    this.$set('userInfo',name,'小红');
  }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值