我最喜欢 NativeScript-Vue 的地方是,我们可以利用两个很棒的框架:NativeScript 和 Vue.js。这就像拥有两件很棒的东西:花生酱和果酱,然后发现将它们混合成三明治会产生更好得多的东西!
我在 Vue.js 世界的最新“发现”是所谓的无渲染组件。它们太棒了!但是当我将它们与 NativeScript 混合使用时……真是美味的组合!
无渲染组件是 Vue 组件,它们实现了一些逻辑或行为,但将视觉界面实现留给其子组件。在 Web 世界中,这意味着无渲染组件不提供任何 HTML 或 CSS。看起来它们可能不是很有用,但在实践中,无渲染组件具有几个优点。
首先,它们不会将你锁定在具体的 UI 中。UI 库经常发生这种情况,随着它们越来越流行,它们的 API 也随之增长,包含各种替代行为或 UI 微调,例如颜色、类、显示/隐藏元素等。使用无渲染组件,库的用户可以完全自由地实现他们想要的 UI。它们也不会将你锁定在 UI 框架中,因此你可以继续使用 Bootstrap、Bulma 或你在代码其他部分中使用的任何其他框架。
相反,无渲染组件将实现重复的行为或逻辑,并且只专注于做好一件事。当我们在本文中探索一些示例时,你将明白我的意思。无渲染组件还允许以声明式的方式向 Vue 的 `` 添加行为,而不是使用命令式 JavaScript 代码。
Vue.js 无渲染组件的秘密在于 作用域插槽。作用域插槽是一种机制,允许组件将数据发送到其插槽。如果父组件发送的是回调函数而不是数据,那么现在客户端插槽可以与父组件进行通信。因此,在实践中,作用域插槽能够实现组件和插槽之间的双向通信。
如果你想了解更多关于无渲染组件及其构建方法的信息,请查看 CSS Tricks 上的这篇文章 和 Adam Wathan 的这篇文章。
所有这些理论都可以在实际代码中得到更好的解释。请查看以下示例。
Adam Wathan 创建的 `
<FetchJson url="https://gist.githubusercontent.com/tralves/89f479ccfdcdd4f720c193e0cd369115/raw/eb17277aa420c70df5130dbd0c27091cec6db4fe/contacts.json">
<GridLayout columns="*" rows="*" slot-scope="{ response: contacts, loading }">
<ActivityIndicator v-if="loading" busy="true" width="100" height="100"/>
<ListView v-else class="list-group"
for="contact in contacts">
<v-template>
<StackLayout class="list-group-item" orientation="horizontal">
<Image class="thumb img-circle" :src="contact.picture.thumbnail"/>
<Label class="m-r-5" :text="contact.name.first"/>
<Label class="font-weight-bold" :text="contact.name.last"/>
</StackLayout>
</v-template>
</ListView>
</GridLayout>
</FetchJson>
在这个例子中,我们使用 `loading` 来显示/隐藏 `
看看!我们发出了 HTTP 请求,检索了结果,并使用没有 JavaScript 的方式检查了请求的状态!我们的代码只需要担心在请求到达后如何将信息呈现给用户。你还可以通过更新 `url` 组件变量来进行连续的请求。
在一个大型应用程序中,你可能希望使用 NativeScript 的 http 模块 或 Axios。这个小例子不止展示了一种发出请求的方式,更重要的是它 **证明了一个观点**。
让我们进一步推动无渲染组件的概念,看看它会带我们走向何方……
Eduardo San Martin Morote 写了无渲染组件 `vue-tweezing`。这个组件对一个变量进行过渡,并将它传递给它的子组件。过渡是指在一段时间内将变量从一个值平滑地转换到另一个值,这可以用来产生动画效果。使用 `vue-tweezing` 与 NativeScript-Vue 的方法如下所示:
<Tweezing ref="tweezing" to="100" duration="500">
<AbsoluteLayout slot-scope="tweenedValue">
<Image top=50 left=250
:width="tweenedValue + 50"
:height="tweenedValue + 50"
src="~/images/NativeScript-Vue.png"/>
</AbsoluteLayout>
</Tweezing>
在这个代码片段中,我们使用过渡后的值来更改图像的 `width` 和 `height`,从而产生一个使图像增大的动画。正如你在下面的视频中看到的,我们可以对各种属性进行动画效果,例如 `opacity`、`font-size`、`left` / `top` 等。
这种动画方法可能无法胜过 NativeScript 动画 的性能,即使在我们的真实设备测试中感觉非常流畅。另一方面,它看起来很容易理解和实现!
`
那么,除了传递变量之外,还封装了一些复杂行为的无渲染组件呢?我们可以更深入地研究……
Adam Wathan 还创建了组件 `
看看我们如何在 NativeScript-Vue 中使用这个组件。
视频显示我们使用该组件实现了两种完全不同的 UI。让我们看看第一个实现,即 **堆叠标签输入**。
<RenderlessTagInput :tags="tags"
@update="(newTags) => tags = newTags"
:remove-on-backspace="false">
<StackLayout slot-scope="{ tags, addTag, removeTag, inputProps, inputEvents }">
<DockLayout class="m-b-20 m-0 p-x-20">
<Button dock="right" class="btn btn-primary" width="100" style="margin-right:0;"
text="Add tag"
@tap="addTag"/>
<TextField hint="Add tag..." returnKeyType="done"
@returnPress="addTag"
@textChange="e => inputEvents.input({ target : { value: e.value}})"
:text="inputProps.value" />
</DockLayout>
<DockLayout class="p-0 p-x-20 m-b-10" v-for="tag in tags" :key="tag" >
<Button dock="right" class="btn btn-primary btn-rounded-sm" width="100" style="margin: 0;"
text="Remove"
@tap="removeTag(tag)"/>
<Label :text="tag" class="t-20 p-y-10"/>
</DockLayout>
</StackLayout>
</RenderlessTagInput>
这里有很多内容。`
由于 `
<RenderlessTagInput :tags="tags"
@update="(newTags) => tags = newTags">
<StackLayout slot-scope="{ tags, addTag, removeTag, inputProps, inputEvents }">
<WrapLayout class="p-x-20">
<StackLayout orientation="horizontal" class="btn btn-primary"
style="margin: 0 10 5 0; padding: 5 5 2 5; border-radius:5"
v-for="tag in tags" :key="tag">
<Label :text="tag" class="t-20 p-r-5"/>
<Label style="margin: 0; color: #386422" text="✖" @tap="removeTag(tag)"/>
</StackLayout>
<TextField hint="Add tag...." returnKeyType="done"
@returnPress="addTag"
@textChange="e => inputEvents.input({ target : { value: e.value}})"
:text="inputProps.value" />
</WrapLayout>
</StackLayout>
</RenderlessTagInput>
你能在该示例中找到作用域变量吗?好!
……无渲染组件太棒了!让我最兴奋的是,Adam 和 Eduardo 为 Web 构建了组件。**他们可能甚至没有想过** 将它们与原生组件一起使用!
Vue.js 生态系统才刚刚开始拥抱这个概念。在这篇文章中,我们使用了 Adam 和 Eduardo 构建的三个组件,但我感觉还会出现更多组件。例如,请查看 Banshee,这是一个只提供无渲染组件的 UI 库。
当然,有些组件是专门为 Web 构建的,我们无法将它们与 NativeScript-Vue 一起使用……但并非所有组件都是如此!让我们享受一下我们的工具箱因添加无渲染组件而变得更加强大这一事实。下次在你的 NativeScript-Vue 应用程序中实现一些 UI 行为时,请查看是否有人已经以无渲染组件的形式实现了该行为。