- 开始时间:2019-04-29
- 目标主要版本:Vue(2.x 或 3.x)Vue Router(3.x 或 4.x)
- 引用 issue:https://github.com/vuejs/vue-router/issues/2611
- 实现的 PR:在 v3.x 和 v4.x 中实现
摘要
- 移除
tagprop - 移除
eventprop - 停止自动分配点击事件给内部锚点
- 添加一个作用域插槽 API
- 添加一个
custom的 prop,以完全自定义router-link的方式渲染
基本范例
<router-link to="/"><Icon>home</Icon> Home</router-link>
动机
当前实现的 Router Link 有许多限制:
这个 RFC 的想法是通过提供一个作用域插槽来解决这些问题,允许开发者根据它们的应用轻松的扩展 Links,并允许库作者提供一个更容易的与 Vue Router 的集成。
具体设计
内容插槽
一个简单的用例是带有内容的插槽(那样嵌套的锚点或者按钮)
<router-link to="/"><Icon>home</Icon> Home</router-link>
这种实现将:
- 生成一个锚点(a)元素并应用相应的属性:
- 带有目的地的 href
- 带有 router-link- active 或 router-link-active 的类(可以通过 prop 或全局选项改变)
- 点击监听器,通过 router.push 或 router.replace 与 event.preventDefault 来触发导航(除了当前连接被点击时使用像 ⌘ 或 Ctrl 这样的修饰词)
- 把任何传递的东西作为锚点的子元素
- 把任何不是 props 的特性传递给
a元素
破坏性改变:
- 不再接受
tag属性 -> 使用作用域插槽来代替(见下文) - 不再接受事件 -> 使用作用域插槽来代替
- 不再作为一个包装器自动寻找里面的第一个
a-> 使用作用域插槽来代替
作用域插槽
一个作用域插槽将获得提供自定义集成所需的每一点信息,并允许任何级别的 active 类、click 监听器、链接等等。这将允许与 Bootstrap(https://getbootstrap.com/docs/4.3/components/navbar/)等 UI 框架更好的整合。我们的想法时创建一个 Vue 组件来避免像 bootstrap-vue 那样的模版(https://bootstrap-vue.js.org/docs/components/navbar/#navbar)。
<router-link to="/" custom v-slot="{ href, navigate, isActive }"><li :class="{ 'active': isActive }"><a :href="href" @click="navigate"><Icon>home</Icon><span class="xs-hidden">Home</span></a></li></router-link>
custom 属性对完全控制 router-link 的渲染是必要的:不渲染包装的 a 元素。
为什么需要 custom 属性:在 Vue3 中,作用域插槽和普通插槽不能互相区分,这意味着 vue router 无法区分这三种情况:
<router-link to="/" v-slot="{ href, navigate, isActive }"></router-link><router-link to="/" v-slot></router-link><router-link to="/">Some Link</router-link>
在这三种情况下,我们都需要渲染插槽的内容,但 router-link 需要知道它是否需要渲染一个包裹的元素。在 Vue2 中,我们可以通过检查 $scopedSlots 来做到这一点,但在 Vue3 中,只有 slots 存在。这意味着在 Vue Router v3 和 Vue Router v4 中的行为略有不同:
- 在 v3 中,
custom属性是必须的(见采纳策略),与v-slot一起。router-link不会用a元素来包装插槽内容。 - 在 v4 中,
custom属性不需要与v-slot一起使用。它控制router-link是否应该用a元素来包装它的插槽内容。 ```vue{{ href }} / /
<a name="JFgXa"></a>### 可访问的变量插槽应该提供在 `router-link` 内部计算的值:- `href`:解析后的相对 url,将被添加到一个锚点标签中(如果提供的话,包含基础,而 route.pullPaht 不包含)- `route`:从 `to` 中解析出规范化的路由位置(与 $route 的形状相同)- `navigate`:触发导航的函数(通常与点击相连)。如果点击被直接按下,也会调用 `preventDefault`- `isActive`:每当应用 `router-link-active` 就是 true。可以通过 `exact` 属性修改- `isExcatActive`:在应用 `router-link-active` 时为 true。可以通过 `exact` 属性修改<a name="GCcXQ"></a>## 移除 `tag` 属性`tag` 属性可以被替换成一个作用域插槽,并使代码更清晰,同时不暴露在任何警告之中。它的移除也将减轻 vue-router 库的负担。```vue<router-link to="/" tag="button"><Icon>home</Icon><span class="xs-hidden">Home</span></router-link>
相当于
<router-link to="/" custom v-slot="{ navigate, isActive, isExactActive }"><button role="link" @click="navigate" :class="{ active: isActive, 'exact-active': isExactActive }"><Icon>home</Icon><span class="xs-hidden">Home</span></button></router-link>
(关于传递给作用域插槽的属性,见上面的解释)
缺点
- 虽然有可能保持现有的行为,只用作用域插槽来暴露一个新的行为,但这仍然会妨碍我们修复当前实现的现有问题。这就是为什么有一些破坏性的变化,以使得事情更加一致。
- 不能访问默认的
router-link类,如router-link-active和router-link-excat-link。
备选方案
``
在这种情况下,采用的策略将是类似的,但警告将告诉用户使用不同的插槽,而不是使用名为custom` 的属性。
- 创建一个新的组件,如 router-link-custom 来区分行为。然而, 这个解决方案比一个属性火一个不同的命名插槽更重(就尺寸而言)。它也没有属性那么合适,因为我们只是改变了组件的一个行为。这两个组件之间的差异太小,不足以证明一个全新的组件是合理的。
采纳策略
- 根据实例记录新插槽的行为。
- 在 v3 版本中,用一条信息废除
tag和event,并链接到文档,然后在 v4 版本中删除。 - 在 v3 中,如果使用作用域插槽时没有提供
custom属性,则警告用户使用custom属性。
没有解决的问题
N/A
