• Vue-Router 源码解析(五) router-link组件的用法及原理


    该组件支持用户在具有路由功能的应用中(点击)导航,默认渲染成带有正确链接的<a>标签,可以通过tag属性生成别的标签。

    它本质上是通过在生成的标签上绑定了click事件,然后执行对应的VueRouter实例的push()实现的,对于router-link组件来说,可以传入以下props:

    • to                                    表示目标路由的链接,当被点击后,内部会立刻把to的值传到router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象
    • tag                                 router-link组件渲染的标签名,默认为a
    • exact                              布尔类型,“是否激活”默认类名的依据是包含匹配
    • append                          布尔类型,设置append属性后,则在当前(相对)路劲前添加基路劲
    • replace                          布尔类型,设置replace后,当点击时会调用router.replace()而不是router.push(),这样导航后不会留下history记录
    • activeClass                   链接激活时使用的CSS类名
    • exactActiveClass          配置当链接被精确匹配的时候应该激活的 class
    • event                            声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组

    举个栗子:

     writer by:大沙漠 QQ:22969969

        <div id="app">
            <router-link to="/info/1">详情页1</router-link>     
            <router-link to="/info/2" event="mouseover">详情页2</router-link>       
            <router-link to="/info/3" tag="p">详情页3</router-link>     
            <hr/>
            <router-view></router-view>
        </div>
        <script>                   
            const info  = { template:'<div>id:{{this.$route.params.id}}</div>'}
            const routes = [                                   
                {path:'/info/:id',component:info,name:'info'},
            ]
            const app = new Vue({                                                     
                el:'#app',
                router:new VueRouter({routes})
            })
        </script>

    渲染后的DOM如下:

    可以看到第二个routerlink组件渲染成了p标签,我们点击时效果如下:

    可以看到详情页3上并没有点击,鼠标移动上去,就会自动切换路由了,这是因为我们传入了event,在上面绑定了onmouseover事件。

    router-link组件自定义了render函数,如下:

    var Link = {
      name: 'RouterLink',
      props: {                          //可以传入的props
        to: {
          type: toTypes,
          required: true
        },
        tag: {
          type: String,
          default: 'a'
        },
        exact: Boolean,
        append: Boolean,
        replace: Boolean,
        activeClass: String,
        exactActiveClass: String,
        event: {
          type: eventTypes,
          default: 'click'                      //默认为click事件
        }
      },
      render: function render (h) {       //router-link组件对应的render函数   h等于大vue上的$createElement函数
        var this$1 = this;
    
        var router = this.$router;                                //获取$router实例
        var current = this.$route;                                //当前的路由对象 
        var ref = router.resolve(this.to, current, this.append);
        var location = ref.location;                              //要跳转的地址,是一个对象    ;例如:{_normalized: true, path: "/login", query: {…}, hash: ""} 
        var route = ref.route;                                    //路由对象
        var href = ref.href;                                      //href属性
     
        var classes = {};                                         //这段代码和linkActiveClass、linkExactActiveClass的配置有关
        var globalActiveClass = router.options.linkActiveClass;
        var globalExactActiveClass = router.options.linkExactActiveClass;
        // Support global empty active class
        var activeClassFallback = globalActiveClass == null
          ? 'router-link-active'
          : globalActiveClass;
        var exactActiveClassFallback = globalExactActiveClass == null
          ? 'router-link-exact-active'
          : globalExactActiveClass;
        var activeClass = this.activeClass == null
          ? activeClassFallback
          : this.activeClass;
        var exactActiveClass = this.exactActiveClass == null
          ? exactActiveClassFallback
          : this.exactActiveClass;
        var compareTarget = location.path
          ? createRoute(null, location, null, router)
          : route;
    
        classes[exactActiveClass] = isSameRoute(current, compareTarget);
        classes[activeClass] = this.exact
          ? classes[exactActiveClass]
          : isIncludedRoute(current, compareTarget);
    
        var handler = function (e) {                          //绑定的事件
          if (guardEvent(e)) {                                  //先调用该函数过滤掉一些和导航无关的事件
            if (this$1.replace) {                               //如果设置了replace属性
              router.replace(location);                           //则执行router.replace切换导航
            } else {
              router.push(location);                              //否则执行router.push更新导航
            }
          }
        };
    
        var on = { click: guardEvent };                               //<router-link>组件默认都支持的click事件,下面会重置的
        if (Array.isArray(this.event)) {
          this.event.forEach(function (e) { on[e] = handler; });
        } else {
          on[this.event] = handler;
        }
    
        var data = {                                              //一般情况下,这里会重置on.click为handler
          class: classes
        };
    
        if (this.tag === 'a') {                                   //如果tag是一个a标签
          data.on = on;
          data.attrs = { href: href };
        } else {                                                  //如果是其它标签          
          // find the first <a> child and apply listener and href
          var a = findAnchor(this.$slots.default);                  //查找第一个<a>标签
          if (a) {                                                  //如果找到了一个a标签
            // in case the <a> is a static node
            a.isStatic = false;
            var aData = a.data = extend({}, a.data);
            aData.on = on;
            var aAttrs = a.data.attrs = extend({}, a.data.attrs);
            aAttrs.href = href;
          } else {                                                  //如果没有找到a标签
            // doesn't have <a> child, apply listener to self
            data.on = on;                                             //则监听自身
          }
        }
    
        return h(this.tag, data, this.$slots.default)             //最后调用$createElement去创建该Vnode
      }
    }

    如果是a标签,在guardEvent函数内会执行preventDefault()函数通知浏览器不要执行与事件相关的动作,所有的动作比如设置hash都是通过VueRouter的内置代码来实现。

  • 相关阅读:
    实战分享 | 你知道这个死锁是怎么产生的吗?
    HDU 3016 线段树区间更新+spfa
    POJ 2828 线段树(想法)
    POJ 2184 01背包+负数处理
    HDU 2955 01背包(思维)
    HDU 1171 背包
    HDU 1561 树形DP入门
    POJ 3694 tarjan 桥+lca
    POJ 2446 最小点覆盖
    POJ 2226 最小点覆盖(经典建图)
  • 原文地址:https://www.cnblogs.com/greatdesert/p/12463333.html
Copyright © 2020-2023  润新知