• vue2.0自定义指令


    前面一片文章说了vue2.0过滤器,其实自定义指令跟过滤器非常相似,单就定义方式而言,其与过滤器完全一致,分为局部指令,和全局指令。不过就是filter改为directive的区别。

    过滤器一般用于对一些常见文本的格式化,而自定义指令主要是为了对底层DOM实现操作,虽然说vue主要是以数据驱动视图,但是总有一些只能操作DOM的应用场景,例如最常见的:拖拽。此时,就是自定义指令大显身手的时候了。

    在移动端,常见这么一个需求,以微信为例,在微信主屏左右滑动时候,可以随着滑动法相更改工具栏,也就是随着滑动,可以在“微信”、“通讯录”、“发现”、“我”之间随意切换。
    这类需求,必须是操作DOM实现的,而无法通过数据来驱动,所以这时候,不管是你使用插件,还是自己定义,必然都是通过自定义指令来实现左右滑动,而切换工具栏的。

    为了方便操作,以tab切换为例:

      <ul class="tabs">
        <router-link to="/home" tag="li"><span>首页</span></router-link>
        <router-link to="/product" tag="li"><span>产品</span></router-link>
        <router-link to="/about" tag="li"><span>关于我们</span></router-link>
      </ul>
    

      在router-view上左右滑动,切换路由:

    <router-view v-swipe-horizontal v-animate-css="'bounceInLeft'" appear></router-view>
    

      我是利用Vue Animate Css来为路由切换添加了一个动画的效果,这里暂不关注。这里需要关注的就是v-swipe-horizontal,“v-”是vue中约定的各种指令的写法,所以其实真正的指令是swipe-horizontal,那么怎么定义swipe-horizontal呢?

      全局定义: 

    // 注册一个全局自定义指令 `v-focus`
    Vue.directive('swipe-horizontal', {
      bind: function (el, binding, vnode, oldVnode) {
        // 各种逻辑操做,这个指令中就是滑动的逻辑
        
      }
    })
    

      局部定义:

      

    swipeHorizontal:{
          bind(el, binding, vnode){
            /**
             * 当前这种做法就完全依赖于路由配置的顺序需要和tab选项卡保持一致,
             * 并且不能随意添加其他位置的路由了
             * 如果通过为每一个路由对象的index使用数组的find方法查找的话,
             * 则需要为路由对象添加index属性
             */
            /* // 利用路由配置数组自身的顺序进行判断
            let routes = vnode.context.$router.options.routes,
                xc = routes.find((item, index)=>{
                  return vnode.context.$route.path == item.path
                }),
                currentRouteIndex = routes.indexOf(xc),
                nextRoute = null,
                nextIndex = null;
              */
            // 利用路有对象自定义的index属性判断
            let routes = vnode.context.$router.options.routes,
                currentRoute = vnode.context.$route.path,
                currentRouteIndex = routes.find((item)=>{
                  return currentRoute == item.path
                }).index,
                nextRoute = null,
                nextIndex = null; 
                var arr = routes.map((item)=>{
                  return item.index
                })
                var max = Math.max(...arr)    
           
    
            el.ontouchstart = (ev)=>{
              let touch = ev.touches[0];
              let disX = touch.clientX - el.offsetLeft;
              let x = disX;
              document.ontouchmove = (ev)=>{
                let touch = ev.touches[0];
                x = touch.clientX ;
              }
              document.ontouchend = () => {
                document.ontouchmove = null;
                document.ontouchend = null;
                console.log("移动距离: ", x, disX)
                /**
                 * 需要利用(routes.length-1)的原因是 路由配置最后一个对象配置了路由重定向
                 */
                // 利用当前的路由对象在整个路由中的序号,即路由配置的数组的顺序
               /*  if (x - disX > 20) {
                  nextIndex = (currentRouteIndex + 1) >= (routes.length-1) ? 0 : (currentRouteIndex + 1);
                } else if(disX - x > 20) {
                  nextIndex = (currentRouteIndex - 1) < 0 ? routes.length -2 : (currentRouteIndex - 1); 
                } */
                nextRoute = routes[nextIndex]
                if (x - disX > 20) {
                  nextIndex = (currentRouteIndex + 1) > max ? 0 : (currentRouteIndex + 1);
                } else if(disX - x > 20) {
                  nextIndex = (currentRouteIndex - 1) < 0 ? max :(currentRouteIndex - 1);
                }
                if (nextIndex != null) {
                  // 利用路有对象自定义的index属性判断
                  nextRoute = routes.find((item)=>{
                    return nextIndex == item.index
                  })
                  //在自定义的指令中,只有通过vnode.context才能获取到vue对象
                  vnode.context.$router.replace(nextRoute)
                }
              }
    

      我这里提供了两种确定路由的模式,主要是确定路由路径的需要。

      一种依赖路由数组的顺序,但是这种情况下,路由数组的顺序就必须与tab选项卡视图展示的数据保持一致。

      另外一种是为每一个路由添加一个index属性,以确定当前tab选项卡展示的顺序。

      自定义指令中,主要逻辑是需要存在于自定义指令的钩子函数中的,而钩子函数又分为bind,inserted,update,componentUpdated,unbind五种,我不知道有多少人能够用到所有的钩子函数,从我的角度来说,常用的钩子函数bind或者inserted,两者选择其一就可以了。

      而钩子函数中的参数:

      

    真的已经很清楚了。

    既然使用自定义指令了,那么尽量不要去修改vue的数据,但是如果非得修改,还是可以通过vnode.context获取到当前的Vue对象的,到这一步,当前这个示例,剩下的也就是一些路由操作,以及基本的数组操作了。

    其实,主要的就是分清楚什么情况下使用自定义指令,自定义指令的钩子函数中el提供了当前操作的dom,binding提供了各类参数,vnode.context提供了当前的vue对象,然后就是逻辑操作了。各类需求不一致,逻辑就不可能相同,所以也没什么好说的了。

      

  • 相关阅读:
    SQL的介绍及MySQL的安装
    git中级技能
    git基本用法
    git基本语法
    出租车数据分析
    使用Spark MLlib进行情感分析
    增量式编码器专题
    vue-loader的简单例子
    node爬虫(转)
    fs-extra 文件管理
  • 原文地址:https://www.cnblogs.com/zhuhuoxingguang/p/8375944.html
Copyright © 2020-2023  润新知