vue自定义指令


1.注册自定义指令(全局和局部)

1> 全局注册

<div id="app">
  <input type="text" placeholder="我是全局自定义指令" v-focus />
</div>

<script>
  Vue.directive("focus", {
    inserted: function (el) {
      el.focus();
    },
  });
  new Vue({
    el: "#app",
  });
</script>

###

2> 局部注册

<div id="app">
  <input type="text" placeholder="我是局部自定义指令" v-focus />
</div>
<script>
  new Vue({
    el: "#app",
    //内部使用
    directives: {
      focus: {
        inserted: function (el) {
          el.focus();
        },
      },
    },
  });
</script>

2.自定义指令传参(单个和多个)

1>单个参数

<div v-focus="scope.row.isdisabled"></div>
<script>
  Vue.directive("focus", function (el, binding) {
    console.log(binding.value); // true
  });
</script>

2>多个参数

<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>

3.钩子函数以及参数

1>钩子函数

inserted,这个就是自定义指令的钩子函数,自定义指令有五个钩子函数:

  1. bind:只调用一次,在指令第一次绑定到元素时调用,可以在这个钩子函数中进行初始化设置;
  2. inserted:被绑定元素插入父节点时调用,在bind后面调用;
  3. update:所在绑定的组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。 调用时指令的值不一定发生改变,通过比较更新前后的值来忽略不必要的模板更新;
  4. componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用;
  5. unbind:只调用一次,指令与元素解绑时调用。
<template>
  <div>
    <h1 v-color="color" v-if="show">{{title}}</h1>
    <button @click="show=false">测试解绑v-color</button>
    <button @click="title='更换title'">更换title</button>
    <button @click="color='blue'">更换color</button>
  </div>
</template>

<script>
  export default {
    name: "HelloWorld",
    data() {
      return {
        color: "red",
        title: "自定义指令",
        show: true,
      };
    },
      directives: {
      color: {
        bind: function () {
          console.log("bind");
        },
        inserted: function (el, binding) {
          console.log("inserted");
          el.style.color = binding.value;
        },
        update: function (el, binding) {
          console.log("update");
          el.style.color = binding.value;
        },
        componentUpdated: function (el, binding) {
          console.log("componentUpdated");
          el.style.color = binding.value;
        },
         unbind: function () {
          console.log("unbind");
        },
      },
      };
</script>

//F5 刷新
bind

inserted

//按钮(更换 title)

update

componentUpdated

//按钮(更换 color)

update

componentUpdated

//按钮(解绑即隐藏)

unbind

2>钩子函数参数

其中el binding就是钩子函数的参数,有 4 个参数:

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

除了**el**之外,其它参数都是只读的,不能对其修改。如果需要在钩子之间共享数据,要通过元素的**dataset**来进行。

4.实际运用

1>图片的加载

需求:图片加载中,需要使用占位图去显示,优化加载图片等待体验。

<div id="app2" class="demo">
  <div v-for="item in imageList">
    <img src="../assets/image/bg.png" alt="默认图" v-image="item.url" />
  </div>
</div>
<script>
  Vue.directive("image", {
    inserted: function (el, binding) {
      //为了真实体现效果,用了延时操作
      setTimeout(function () {
        el.setAttribute("src", binding.value);
      }, Math.random() * 1200);
    },
  });
  new Vue({
    el: "#app2",
    data: {
      imageList: [
        {
          url: "http://consumer-img.huawei.com/content/dam/huawei-cbg-site/greate-china/cn/mkt/homepage/section4/home-s4-p10-plus.jpg",
        },
        {
          url: "http://consumer-img.huawei.com/content/dam/huawei-cbg-site/greate-china/cn/mkt/homepage/section4/home-s4-watch2-pro-banner.jpg",
        },
        {
          url: "http://consumer-img.huawei.com/content/dam/huawei-cbg-site/en/mkt/homepage/section4/home-s4-matebook-x.jpg",
        },
      ],
    },
  });
</script>

###

2>input 的聚焦

需求:点击输入框旁边的按钮,input 变为可编辑状态,并且获取焦点。失焦时,input 变为不可编辑状态。

<template>
  <div>
    <el-table
      :data="tableData"
      v-loading="listLoading"
      ref="TableRow"
      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
      style="width: 100%"
      @select="handleSelectionChange"
      :row-key="getRowKeys"
      @row-click="RowClick"
    >
      <el-table-column
        align="center"
        width="50"
        type="selection"
      ></el-table-column>
      <el-table-column prop="name" label="商品" width="175"></el-table-column>
      <el-table-column prop="upc" label="商品条码"></el-table-column>
      <el-table-column prop="vipPrice1" label="会员价1(元)">
        <template slot-scope="scope">
          <div class="priceChangeWay">
            <el-input
              v-model="scope.row.vipPrice1"
              v-focus
              @blur="cope.row.isdisabled1=true"
              :disabled="scope.row.isdisabled1"
            >
            </el-input>
            <span
              ><i
                slot="suffix"
                @click.stop="scope.row.isdisabled1=false"
                v-if="scope.row.isdisabled1"
                class="el-input__icon el-icon-edit"
              ></i
            ></span>
          </div>
        </template>
      </el-table-column>
      <el-table-column prop="vipPrice2" label="会员价2(元)">
        <template slot-scope="scope">
          <div class="priceChangeWay">
            <el-input
              v-model="scope.row.vipPrice2"
              v-focus
              @blur="cope.row.isdisabled2=true"
              :disabled="scope.row.isdisabled2"
            >
            </el-input>
            <span
              ><i
                slot="suffix"
                @click.stop="scope.row.isdisabled2=false"
                v-if="scope.row.isdisabled2"
                class="el-input__icon el-icon-edit"
              ></i
            ></span>
          </div>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
  export default {
    data: {
      return {
          tableData:[]
          }
      },
    directives: {
      focus: {
        // 指令的定义
        update: function (el, binding) {
          // console.log(el.children[0], binding.value)
          // 聚焦元素
          el.focus()
          // element-ui
          el.children[0].focus()
          // 元素有变化,如show或者父元素变化可以加延时或判断
          setTimeout(_ => {
            el.children[0].focus()
          })
        }
      },
      methods:{
           // 读取商品库数据
        ReadGoodsData () {
          this.listLoading = true
          queryShopProductSkuByPage(this.queryData).then(res => {
            this.listLoading = false
            res.results.map(item => {
              item.isdisabled1 = true
              item.isdisabled2 = true
              item.vipPrice1 = ''
              item.vipPrice2 = ''
              return item
            })
            this.tableData = res.results || []
          }).catch(err => {
            this.listLoading = false
            console.log(err)
          })
        }
      }
    }
</script>

3>更多自定义指令资源

想了解更多自定义指令资源,请了解此篇文章。


文章作者:   leader755
版权声明:   本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 leader755 !
评论
  目录