diff --git a/Makefile b/Makefile index 3fc827c410..a0d74bbd9a 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,14 @@ all: update deploy deploy: - rm -f db.json + rm -rf public db.json hexo generate - cp -R ./todomvc public/examples hexo deploy update: cd ../vue && \ git checkout -- dist && \ - git checkout next && \ + git checkout dev && \ npm run build cp ../vue/dist/vue.min.js themes/vue/source/js/vue.min.js cp ../vue/dist/vue.js themes/vue/source/js/vue.js diff --git a/README.md b/README.md index 37ecaecb30..1b7a6a0dd9 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,132 @@ -# vuejs-2.0 翻译计划 +# Vue.js 2.0 翻译 +这个厂库只用来协作翻译 -## 翻译字典 +[vue2 文档厂库](https://github.com/hayeah/vuejs.org) -先参考 [vuejs-1.0 中文文档](http://cn.vuejs.org/),如有需要再建立一个额外的文档。 +## 翻译规范(参考了 [vue 1.0 翻译规范](https://github.com/vuejs/cn.vuejs.org/blob/lang-zh/CONTRIBUTING.md#翻译) ) +* 使用中文的符号 +* 汉字,字母,数字等之间以空格隔开。 +* 专有词注意大小写,如 HTML,CSS,JavaScript。 +* 代码只翻译注释。 + +[阮一峰关于中文技术文档的规范](https://github.com/ruanyf/document-style-guide) + +## 翻译字典(更新中) + +英文 | 中文 | 备注 | +---- | ---- | ---- | +(single) source of truth | (单一)数据源 +attribute | 属性 | 主体: DOM 元素 +benchmark | 测试基准 +companion library | 插件库 +component | 组件 +console | 控制台 +core | 内核 +declarative | 声明式 +directive | 指令 +example | 示例 +fallback content | 替换内容 | 根据 MDN 文档 +filter | 过滤器 +for example | 例如 +functional | 函数式 | e.g. `functional component` :函数式组件 +guide | 教程 +incrementally adoptable | 增量式使用(转为动词) +interpolation | 插值 +item | 项 | e.g. 列表项,数组项 +learning curve | 学习曲线 +listener, listen | 侦听器;侦听 +mutation | 突变 +non-trivial app | 正常应用 +overhead | 额外开销 +parent scope | 父级作用域 +progressive | 渐进式 +prop | 属性 | 主体:Vue 组件 +property | 属性 | 主体:javascript 对象 +reactive | 响应式的 +render function | 渲染函数 +see also | 另见 +single page application, spa | 单页应用 +transition effect | 过渡动画 +transition | 过渡动画 | [小右的文章](http://www.html-js.com/article/1833) +virtual DOM | 虚拟 DOM +wrap | 包裹 + +参考资料: +- [小右的专栏](http://www.html-js.com/article/column/99) +- [小右的另一个专栏](http://www.zhihu.com.question.39879941.cmiiu.com/?people/evanyou/posts) +- [小右对 Vue 2 的介绍@Qcon](http://www.infoq.com/cn/articles/vue-2-progressive-front-end-solution) +- [vuejs-1.0 中文文档](http://cn.vuejs.org/) + ## 协作形式 翻译者: -* 请从标记为 `待领取` 的 issues 中领取任务,写清楚预估的 DDL。 +* 请从标记为 `待领取` 的 issues 中领取任务,写什么时候能完成。 * 如果超过预估时间无法完成请在 issue 中 at 协调员,说明接替者信息或请协调员重新分配该任务; * 完成任务后提交 PR -* 若 PR 被标记为 `待修改`,根据修改一件修改后删除标记,分配给协调员 +* 若 PR 被标记为 `待修改`,根据反馈修改后删除标记,分配给协调员 +* 请保留英文原文,方便校对。 + +协调员:[@hymRedemption](https://github.com/hymRedemption) -协调员 * 将无状态的 PR 分配给校对员,标记为待校对 * 若 `待合并` 的 PR 可以合并,则直接合并。合并后在 README 更新进度表,关闭相关的 issues * 若 `待合并` 的 PR 不能合并,分配给 PR 提交者并将 PR 标记为 `待修改` -校对员: +校对员: [@Egoist](https://github.com/egoist), [@mrwiredancer](https://github.com/Mr-Wiredancer) + * 对 `待校对` 的 PR 进行校对 * 校对通过则将 PR 改为`待合并`,并分配给协调员 * 校对不通过则将 PR 改为 `待修改`,并分配给 PR 提交者 -## 进度表 -文章 | 翻译 | 校对 | 状态 | ----- | ---- | ---- | ---- | -示例/示例| [mrwiredancer](https://github.com/Mr-Wiredancer) | | 进行中 | -api/index| -guide/class-and-style| -guide/comparison | -guide/components | - -#vuejs.org - -This site is built with [hexo](http://hexo.io/). Site content is written in Markdown format located in `src`. Pull requests welcome! +## 进度表 (最后更新:2016-10-28 15:22) -## Developing - -Start a dev server at `localhost:4000`: - -``` -$ npm install -g hexo-cli -$ npm install -$ hexo server -``` +文章 | 翻译 | 校对 | 状态 | +---- | ---- | ---- | ---- | +api/index#Global Config | [mrwiredancer](https://github.com/Mr-Wiredancer) | egoist | ~~已完成~~ +api/index#Global API | pandazki |[mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +api/index#Options/Data |[milkmeowo](https://github.com/milkmeowo)| egoist| ~~已完成~~ +api/index#Options/DOM |[milkmeowo](https://github.com/milkmeowo)| [mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +api/index#Options/Lifecycle Hooks |[milkmeowo](https://github.com/milkmeowo)| hayeah | ~~已完成~~ +api/index#Options/Assets|[milkmeowo](https://github.com/milkmeowo)| [mrwiredancer](https://github.com/Mr-Wiredancer)| ~~已完成~~ +api/index#Options/misc |[milkmeowo](https://github.com/milkmeowo)| hayeah | ~~已完成~~ +api/index#Instance Properties | [dmxj](https://github.com/dmxj) |[mrwiredancer](https://github.com/Mr-Wiredancer)| ~~已完成~~ +api/index#Instance Methods/Data | [alfredcc](https://github.com/alfredcc) |egoist| ~~已完成~~ +api/index#Instance Methods/Eevents |[dmxj](https://github.com/dmxj)| [mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +api/index#Instance Methods/Lifecycle |[dmxj](https://github.com/dmxj)|[mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +api/index#Directives |[dmxj](https://github.com/dmxj)|[mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +api/index#Special Attributes |[aliencyl7](https://github.com/aliencyl7)| [mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +api/index#Built-in Components |[milkmeowo](https://github.com/milkmeowo)| [mrwiredancer](https://github.com/Mr-Wiredancer)|~~已完成~~ +api/index#VNode Interface |[milkmeowo](https://github.com/milkmeowo)| | ~~已完成~~ +api/index#Server-Side Rendering |[milkmeowo](https://github.com/milkmeowo)| hayeah | ~~已完成~~ +guide/installation | [mrwiredancer](https://github.com/Mr-Wiredancer) | egoist | ~~已完成~~ +guide/index | [mrwiredancer](https://github.com/Mr-Wiredancer) |pandazki | ~~已完成~~ +guide/instance | [baurine](https://github.com/baurine)| [mrwiredancer](https://github.com/Mr-Wiredancer)| ~~已完成~~ +guide/syntax |[baurine](https://github.com/baurine)|milkmeowo| ~~已完成~~ +guide/computed |[gongph](https://github.com/gongph) |[mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +guide/class-and-style | fszer | [mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +guide/conditional |[MechanicianW](https://github.com/MechanicianW) | hayeah | ~~已完成~~ +guide/list | [mrwiredancer](https://github.com/Mr-Wiredancer) | coderkwong | ~~已完成~~ +guide/events | [mrwiredancer](https://github.com/Mr-Wiredancer) | [milkmeowo](https://github.com/milkmeowo)| ~~已完成~~ +guide/forms | jacelynfish | milmeowo | ~~已完成~~ +guide/components |[MechanicianW](https://github.com/MechanicianW) |[mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +guide/transitions | jacelynfish | codekwong, mrwiredancer | ~~已完成~~ +guide/transitioning-state |[gongph](https://github.com/gongph)| [mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +guide/render-function | [pandazki](https://github.com/pandazki) | [mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +guide/reactivity |[pandazki](https://github.com/pandazki) |[mrwiredancer](https://github.com/Mr-Wiredancer) |~~已完成~~ +guide/custom-directive |[lsslu](https://github.com/lsslu)| milkmeowo, [mrwiredancer](https://github.com/Mr-Wiredancer) |~~已完成~~ +guide/mixins | [leon0204](https://github.com/leon0204) | hayeah | ~~已完成~~ +guide/plugins |[leon0204](https://github.com/leon0204) | [milkmeowo](https://github.com/milkmeowo), hayeah|~~已完成~~ +guide/single-file-components | [mrwiredancer](https://github.com/Mr-Wiredancer) | [pandazki](https://github.com/pandazki) | ~~已完成~~ +guide/deployment | [mrwiredancer](https://github.com/Mr-Wiredancer) | coderkwong | ~~已完成~~ +guide/routing |[lsslu](https://github.com/lsslu)| [milkmeowo](https://github.com/milkmeowo), [mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +guide/state-management | mrwiredancer | coderkwong | ~~已完成~~ +guide/unit-testing |[Yogi-Jiang](https://github.com/Yogi-Jiang) | hayeah | ~~已完成~~ +guide/ssr | gongph | [mrwiredancer](https://github.com/Mr-Wiredancer) | ~~已完成~~ +guide/migration |[RiXiong](https://github.com/RiXiong)| mrwiredancer|~~已完成~~ +guide/migration-vue-router |[mrwiredancer](https://github.com/Mr-Wiredancer) | [pandazki](https://github.com/pandazki) | ~~已完成~~ +guide/migration-vuex | [mrwiredancer](https://github.com/Mr-Wiredancer) | coderkwong | ~~已完成~~ +guide/comparison | [mrwiredancer](https://github.com/Mr-Wiredancer) | [milkmeowo](https://github.com/milkmeowo) | ~~已完成~~ +guide/join |[leon0204](https://github.com/leon0204)| [mrwiredancer](https://github.com/Mr-Wiredancer)| ~~已完成~~ diff --git a/_config.yml b/_config.yml index b886356dfc..182ed390e0 100644 --- a/_config.yml +++ b/_config.yml @@ -97,7 +97,7 @@ markdown: ## Docs: http://zespia.tw/hexo/docs/deployment.html deploy: type: git - repository: git@github.com:vuejs/rc.vuejs.org.git + repository: git@github.com:vuejs/vuejs.org.git feed: type: atom diff --git a/src/CNAME b/src/CNAME index 79fd262475..998cc417c8 100644 --- a/src/CNAME +++ b/src/CNAME @@ -1 +1 @@ -rc.vuejs.org +vuejs.org diff --git a/src/_posts/why-no-template-url.md b/src/_posts/why-no-template-url.md index fe40415646..f6fbabe2dd 100644 --- a/src/_posts/why-no-template-url.md +++ b/src/_posts/why-no-template-url.md @@ -13,7 +13,7 @@ First, it allows us to write our template in a separate HTML file. This gives us Second, because `templateURL` loads the template via Ajax at runtime, you don't need a build step in order to split up your files. This is convenient during development, but comes at a serious cost when you want to deploy it to production. Before HTTP/2 is universally supported, the number of HTTP requests is still probably the most critical factor in your app's initial load performance. Now imagine you use `templateURL` for every component in your app - the browser needs to perform dozens of HTTP requests before even being able to display anything! In case you don't know, most browsers limit the number of parallel requests it can perform to a single server. When you exceed that limit, your app's initial rendering will suffer for every extra round trip the browser has to wait for. Sure, there are build tools that can help you pre-register all those templates in `$templateCache` - but that shows us a build step is, in fact, inevitable for any serious frontend development. -So, without `templateURL`, how do we deal with the development experience problem? Writing templates as inline JavaScript strings is terrible, faking templates with ` + ``` Then you can start writing Vue code and even ship the minified version to production without feeling guilty or having to worry about performance problems. +然后你就可以开始写 Vue 代码,甚至可以把最小化的版本直接推到生产环境,完全不需要担心性能问题。 Since you don't need to know about JSX, ES2015, or build systems to get started with Vue, it also typically takes developers less than a day reading [the guide](/guide) to learn enough to build non-trivial applications. +要上手 Vue,你不需要了解 JSX,ES2015 或者构建系统。,通常你只需要花不到一天来阅读 [教程](/guide),就可以开始写一个实际应用。 -### Native Rendering +### 原生渲染 (Native Rendering) ReactNative enables you to write native-rendered apps for iOS and Android using the same React component model. This is great in that as a developer, you can apply your knowledge of a framework across multiple platforms. On this front, Vue has an official collaboration with [Weex](https://alibaba.github.io/weex/), a cross-platform UI framework developed by Alibaba Group, which uses Vue as its JavaScript framework runtime. This means with Weex, you can use the same Vue component syntax to author components that can not only be rendered in the Browser, but also natively on iOS and Android! +ReactNative 让你可以使用同样的 React 组件模型,编写原生渲染的 iOS 和 Android 应用。这对于开发者来说很棒,因为你可以用一个框架写跨平台的应用。在这一点上,Vue 已经和阿里巴巴的 [Weex](https://alibaba.github.io/weex/) 达成官方合作,Weex 会使用 Vue 来作为 JavaScript 的框架运行时。这意味着你可以在 Weex 中使用 Vue 的语法来编写部件,这些部件不仅可以在浏览器上运行,也可以在 iOS 和 Android 平台上以原生的方式运行。 -At this moment, Weex is still in active development and is not as mature and battle-tested as ReactNative, but its development is driven by the production needs by the largest e-commmerce business in the world, and the Vue team will also actively collaborate with the Weex team to ensure a smooth experience for Vue developers. +At this moment, Weex is still in active development and is not as mature and battle-tested as ReactNative, but its development is driven by the production needs of the largest e-commerce business in the world, and the Vue team will also actively collaborate with the Weex team to ensure a smooth experience for Vue developers. +在写这篇文章的时候,Weex 仍然处于活跃的开发状态,还没有达到 ReactNative 的成熟度,不过它的开发是由世界上最大的电子商务公司的生产需求所驱动的,而 Vue 团队也会积极地和 Weex 团队合作,确保为开发者带来流畅的体验。 -### With MobX +### 与 MobX 一起使用 (With MobX) MobX has become quite popular in the React community and it actually uses a nearly identical reactivity system to Vue. To a limited extent, the React + MobX workflow can be thought of as a more verbose Vue, so if you're using that combination and are enjoying it, jumping into Vue is probably the next logical step. +MobX 在 React 社区中已经相当流行,而且它使用了几乎跟 Vue 一摸一样的响应式系统。在某种程度上,可以把 React + Mobx 当作一个繁琐版的 Vue。所以如果你觉得这个组合用得很爽,那么使用 Vue 是一个很自然的选择。 ## Angular 1 Some of Vue's syntax will look very similar to Angular (e.g. `v-if` vs `ng-if`). This is because there were a lot of things that Angular got right and these were an inspiration for Vue very early in its development. There are also many pains that come with Angular however, where Vue has attempted to offer a significant improvement. +Vue 的一些语法看起来和 Angular 很类似(比如 `v-if` 和 `ng-if`)。这是因为 Angular 有很多做的很好的地方,而 Vue 在早期开发阶段从 Angular 获得了很多灵感。不过,使用 Angular 也有很多蛋疼的地方,而 Vue 在这些方面提供了大幅度的改善。 -### Complexity +### 复杂性 (Complexity) Vue is much simpler than Angular 1, both in terms of API and design. Learning enough to build non-trivial applications typically takes less than a day, which is not true for Angular 1. +无论是 API 还是设计思路,Vue 比 Angular 1 都要简单得多。使用 Vue 构建一个实际应用,只需要花不到一天的时间来学习,而 Angular 1 就不行了。 -### Flexibility and Modularity +### 灵活性和模块化 (Flexibility and Modularity) Angular 1 has strong opinions about how your applications should be structured, while Vue is a more flexible, modular solution. While this makes Vue more adaptable to a wide variety of projects, we also recognize that sometimes it's useful to have some decisions made for you, so that you can just get started coding. +Angular 1 对于你的项目结构有着很强的制约,而 Vue 则更为灵活且模块化。虽然这让 Vue 可以适应很多不同类型的项目,不过我们也意识到,有时候开发者不希望考虑太多,只是想直接开始写代码。 That's why we offer a [Webpack template](https://github.com/vuejs-templates/webpack) that can set you up within minutes, while also granting you access to advanced features such as hot module reloading, linting, CSS extraction, and much more. +这就是为什么我们提供了一个 [Webpack 模版](https://github.com/vuejs-templates/webpack),它可以在几分钟之内帮你配置好环境,同时提供了模块热加载,linting,CSS 提取等高级功能。 -### Data binding +### 数据绑定 (Data binding) Angular 1 uses two-way binding between scopes, while Vue enforces a one-way data flow between components. This makes the flow of data easier to reason about in non-trivial applications. +Angular 1 在不同域之间采用双向绑定,而 Vue 强制在组件之间使用单向数据流。这样会让应用的数据流更加清晰。 -### Directives vs Components +### 指令和组件 (Directives vs Components) Vue has a clearer separation between directives and components. Directives are meant to encapsulate DOM manipulations only, while components are self-contained units that have their own view and data logic. In Angular, there's a lot of confusion between the two. +Vue 清楚地区分了指令和组件。指令是用来封装 DOM 操作的,而组件是独立的存在,包含了自己的视图和数据逻辑。在 Angular 中,这两者经常会混在一起。 -### Performance +### 性能 (Performance) Vue has better performance and is much, much easier to optimize because it doesn't use dirty checking. Angular 1 becomes slow when there are a lot of watchers, because every time anything in the scope changes, all these watchers need to be re-evaluated again. Also, the digest cycle may have to run multiple times to "stabilize" if some watcher triggers another update. Angular users often have to resort to esoteric techniques to get around the digest cycle, and in some situations, there's simply no way to optimize a scope with many watchers. +Vue 有着更好的性能,并且更容易优化,因为 Vue 没有使用脏检查。Angular 1 在有大量监视器的时候会变的很慢,因为每一次在域内的变化,都会导致所有的监视器重新计算。而且,如果某些监视器触发了其它更新,那么 digest cycle 要多次计算才能得出最终的结果。Angular 的开发者经常需要用到一些黑魔法来绕开 digest cycle,而在某些情况下,根本没有办法对拥有多个监视器的域进行优化。 Vue doesn't suffer from this at all because it uses a transparent dependency-tracking observation system with async queueing - all changes trigger independently unless they have explicit dependency relationships. +而 Vue 就没有这个问题,因为 Vue 使用了一个透明的,基于异步队列的依赖跟踪观察系统,所有的变化都会独立触发,除非它们有明确的依赖关系。 Interestingly, there are quite a few similarities in how Angular 2 and Vue are addressing these Angular 1 issues. +有趣的是,Angular 2 和 Vue 用了不少相似的方式,来解决这些 Angular 1 的问题。 ## Angular 2 We have a separate section for Angular 2 because it really is a completely new framework. For example, it features a first-class component system, many implementation details have been completely rewritten, and the API has also changed quite drastically. +我们给 Angular 2 一个单独的篇幅,因为它是一个跟 Angular 1 完全不同的框架。比如,它具备一流的组件系统,许多实现细节被彻底重写,API 也发生了大幅度的改变。 ### TypeScript While Angular 1 could be used for smaller applications, Angular 2 has shifted focus to best facilitate large enterprise applications. As part of this, it almost requires TypeScript, which can be very useful for developers that desire the type safety of languages such as Java and C#. +虽然 Angular 1 还能用于构建一些小型应用,Angular 2 已经把注意力放在支持大型的企业级应用上。出于这个原因,Typescript 几乎变成了 Angular 2 的必需品,它对于那些渴望类型安全机制(比如 Java 和 C#)的开发者非常有用。 -Vue is also well-suited to [enterprise environments](https://github.com/vuejs/awesome-vue#enterprise-usage) and can even be used with TypeScript via our [official typings](https://github.com/vuejs/vue/tree/next/types) and [user-contributed decorators](https://github.com/itsFrank/vue-typescript), though it's definitely optional in our case. +Vue is also well-suited to [enterprise environments](https://github.com/vuejs/awesome-vue#enterprise-usage) and can even be used with TypeScript via our [official typings](https://github.com/vuejs/vue/tree/dev/types) and [user-contributed decorators](https://github.com/itsFrank/vue-typescript), though it's definitely optional in our case. +Vue 对于[企业环境](https://github.com/vuejs/awesome-vue#enterprise-usage)也十分适用,你甚至可以通过[官方的类型声明](https://github.com/vuejs/vue/tree/dev/types) 和 [用户贡献的装饰符](https://github.com/itsFrank/vue-typescript),来和 TypeScript 搭配使用。不过 TypeScript 对于 Vue 来说不是必需的。 -### Size and Performance +### 文件大小和性能 (Size and Performance) In terms of performance, both frameworks are exceptionally fast and there isn't enough data from real world use cases to make a verdict. However if you are determined to see some numbers, Vue 2.0 seems to be ahead of Angular 2 according to this [3rd party benchmark](http://stefankrause.net/js-frameworks-benchmark4/webdriver-ts/table.html). +从性能的角度,两个框架都非常快,目前我们并没有足够的数据来说明这两者之间的差异。如果你确实想看一些这方面的数据,根据这个 [第三方的测试基准](http://stefankrause.net/js-frameworks-benchmark4/webdriver-ts/table.html),Vue 2.0 好像的确胜过 Angular 2。 Size wise, although Angular 2 with offline compilation and tree-shaking is able to get its size down considerably, a full-featured Vue 2.0 with compiler included (23kb) is still lighter than a tree-shaken bare-bone example of Angular 2 (50kb). And do note the Angular 2 app's size is small due to tree-shaking, which removes code for features that you are not using. It will eventually grow back to its actual size as you import and use more features from the framework. +从文件大小的角度,虽然 Angular 2 用离线编译和 tree-shaking 可以大大降低文件大小。但一个包含了编译器的完整的 Vue 2.0 (23kb) 依然比 Angular 2 (50kb) 要小。但是要注意,Angular 2 的体积缩小是因为 tree-shaking,这意味着你没有用到的代码会被删除掉。如果你导入且使用了更多的 Angular 2 特性,它最终会变回原来的大小。 -### Flexibility +### 灵活性 (Flexibility) Vue is much less opinionated than Angular 2, offering official support for a variety of build systems, with no restrictions on how you structure your application. Many developers enjoy this freedom, while some prefer having only one Right Way to build any application. +Vue 相对 Angular 2 而言更加中立,它为不同的构建系统提供了官方支持,而且没有对你的项目结构提出任何限制。许多开发者享受这种自由度,但同时也有一些开发者喜欢“只有一种正确做法”的开发方式。 -### Learning Curve +### 学习曲线 (Learning Curve) To get started with Vue, all you need is familiarity with HTML and ES5 JavaScript (i.e. plain JavaScript). With these basic skills, you can start building non-trivial applications within less than a day of reading [the guide](/guide). +要上手 Vue,你只需要熟悉 HTML 和 ES5 (也就是普通的 JavaScript)。有了这些基本知识,花上不到一天来阅读 [教程](/guide),你就可以开始开发了。 -Angular 2's learning curve is much steeper. Even without TypeScript, their [Quickstart guide](https://angular.io/docs/js/latest/quickstart.html) starts out with an app that uses ES2015 JavaScript, NPM with 18 dependencies, 4 files, and over 3,000 words to explain it all - just to say Hello World. It's an understatement to say that [Vue's Hello World](index.html#Hello-World) is considerably simpler. It's so trivial in fact, that we don't even dedicate a whole page in the guide to it. +Angular 2's learning curve is much steeper. Even without TypeScript, their [Quickstart guide](https://angular.io/docs/js/latest/quickstart.html) starts out with an app that uses ES2015 JavaScript, NPM with 18 dependencies, 4 files, and over 3,000 words to explain it all - just to say Hello World. It's an understatement to say that [Vue's Hello World](https://jsfiddle.net/chrisvfritz/50wL7mdz/) is considerably simpler. It's so trivial in fact, that we don't even dedicate a whole page in the guide to it. +Angular 2 的学习曲线则要陡峭的多。即使是有 TypeScript 的帮助,它们的 [上手教程](https://angular.io/docs/js/latest/quickstart.html) 也还是使用了 ES2015,拥有 18 个 NPM 依赖,4个文件,以及超过 3000 个英文单词来解释,而这仅仅是为了写 Hello World 程序而已。相比之下,[Vue 的 Hello World 程序](https://jsfiddle.net/chrisvfritz/50wL7mdz/) 就超级简单,我们甚至都没有花费教程里的篇幅来介绍它。 ## Ember Ember is a full-featured framework that is designed to be highly opinionated. It provides a lot of established conventions and once you are familiar enough with them, it can make you very productive. However, it also means the learning curve is high and flexibility suffers. It's a trade-off when you try to pick between an opinionated framework and a library with a loosely coupled set of tools that work together. The latter gives you more freedom but also requires you to make more architectural decisions. +Ember 是一个全能框架,有着强烈的开发主张。它提出了很多约定,如果你对它们足够熟悉,这会让你可以非常高效地进行开发。不过,这也意味着它的学习曲线非常陡峭,而且灵活性不高。在一个具有强烈主张的框架(Ember),和一系列松散耦合的工具(Vue)之间做出选择时,你必需进行权衡。后者给你更多的自由度,但是需要自己做更多的架构上的决定。 That said, it would probably make a better comparison between Vue core and Ember's [templating](https://guides.emberjs.com/v2.7.0/templates/handlebars-basics/) and [object model](https://guides.emberjs.com/v2.7.0/object-model/) layers: +也就是说,我们最好来比较一下 Vue 的内核,以及 Ember 的 [模版](https://guides.emberjs.com/v2.7.0/templates/handlebars-basics/) 与 [对象模型](https://guides.emberjs.com/v2.7.0/object-model/) 层: - Vue provides unobtrusive reactivity on plain JavaScript objects and fully automatic computed properties. In Ember, you need to wrap everything in Ember Objects and manually declare dependencies for computed properties. +Vue 以一种自然的方式,在普通 JavaScript 对象上提供了响应式特性。而在 Ember 里面,你需要将所有东西都封装成 Ember 对象,手动声明计算属性的依赖。 -- Vue's template syntax harnesses the full power of JavaScript expressions, while Handlebars' expression and helper syntax is quite limited in comparison. +- Vue's template syntax harnesses the full power of JavaScript expressions, while Handlebars' expression and helper syntax is intentionally quite limited in comparison. +Vue 的模版语法充分利用了 JavaScript 表达式的能力,而相比之下, Hnadlebar 则有意限制表达式和 helper 语法。 - Performance-wise, Vue outperforms Ember by a fair margin, even after the latest Glimmer engine update in Ember 2.0. Vue automatically batches updates, while in Ember you need to manually manage run loops in performance-critical situations. +从性能的角度,Vue 远胜 Ember,即使在 Ember 2.0 最新的 Glimmer 引擎更新之后。Vue 会自动地批量处理更新,而在追求性能的场景下, Ember 需要你手动管理运行循环。 ## Knockout Knockout was a pioneer in the MVVM and dependency tracking spaces and its reactivity system is very similar to Vue's. Its [browser support](http://knockoutjs.com/documentation/browser-support.html) is also very impressive considering everything it does, with support back to IE6! Vue on the other hand only supports IE9+. +Knockout 是 MVVM 和依赖跟踪的先驱,它的响应式系统和 Vue 十分相似。考虑到它提供的功能,Knockout 的[浏览器支持](http://knockoutjs.com/documentation/browser-support.html) 可以说相当的出色,甚至还支持 IE6!而 Vue 则只支持 IE9+。 Over time though, Knockout development has slowed and it's begun to show its age a little. For example, its component system lacks a full set of lifecycle hooks and although it's a very common use case, the interface for passing children to a component feels a little clunky compared to [Vue's](components.html#Content-Distribution-with-Slots). +不过随着时间推移,Knockout 的开发速度已经慢了下来。比如,它的组件系统缺少一整套生命周期钩子,传递子组件的接口相对于 [Vue](components.html#Content-Distribution-with-Slots) 来说也非常笨重,即使它经常会被用到。 There also seem to be philosophical differences in the API design which if you're curious, can be demonstrated by how each handles the creation of a [simple todo list](https://gist.github.com/chrisvfritz/9e5f2d6826af00fcbace7be8f6dccb89). It's definitely somewhat subjective, but many consider Vue's API to be less complex and better structured. +在 API 设计上两者也有一些哲学上的差异,你可以在下面这个[简单 todo 列表](https://gist.github.com/chrisvfritz/9e5f2d6826af00fcbace7be8f6dccb89)的示例代码里看到这些差异。虽然有点主观,但很多人都认为 Vue 的 API 要更简单优雅。 ## Polymer Polymer is yet another Google-sponsored project and in fact was a source of inspiration for Vue as well. Vue's components can be loosely compared to Polymer's custom elements and both provide a very similar development style. The biggest difference is that Polymer is built upon the latest Web Components features and requires non-trivial polyfills to work (with degraded performance) in browsers that don't support those features natively. In contrast, Vue works without any dependencies or polyfills down to IE9. +Polymer 是另一个 Google 赞助的项目,实际上它也是 Vue 的一个灵感来源。Vue 的组件可以跟 Polymer 的自定义元素粗略类比,两者都有类似的开发风格。最大的区别在于 Polymer 是基于 Web Components 特性,在还没有支持这个特性的浏览器上,需要引入一个不小的 polyfill,降低了它的性能。相比之下,Vue 不需要任何依赖和 polyfill,就可以在 IE9+ 的浏览器上运行。 In Polymer 1.0, the team has also made its data-binding system very limited in order to compensate for the performance. For example, the only expressions supported in Polymer templates are boolean negation and single method calls. Its computed property implementation is also not very flexible. +在 Polymer 1.0中,出于性能考虑,开发团队将数据绑定系统设计得非常局限。比如,在 Polymer 模版中的表达式只支持布尔值的否操作和普通的函数调用。它对于计算属性的实现也比较死板。 Polymer custom elements are authored in HTML files, which limits you to plain JavaScript/CSS (and language features supported by today's browsers). In comparison, Vue's single file components allows you to easily use ES2015+ and any CSS preprocessors you want. +Polymer 的自定义元素是在 HTML 文件里面编写的,所以你只能用普通的 JavaScript/CSS (以及浏览器所支持的属性)。而 Vue 的单文件组件让你可以轻松地使用 ES2015+ 以及你所偏好的 CSS 预编译器。 When deploying to production, Polymer recommends loading everything on-the-fly with HTML Imports, which assumes browsers implementing the spec, and HTTP/2 support on both server and client. This may or may not be feasible depending on your target audience and deployment environment. In cases where this is not desirable, you will have to use a special tool called Vulcanizer to bundle your Polymer elements. On this front, Vue can combine its async component feature with Webpack's code-splitting feature to easily split out parts of the application bundle to be lazy-loaded. This ensures compatibility with older browsers while retaining great app loading performance. +在部署到生产环境时,Polymer 推荐你使用 HTML 导入加载所有资源,但浏览器必需支持相关的特性,而且浏览器和客户端都要支持 HTTP/2。考虑到目标用户和部署环境,有时候这是不现实的。在这种情况下,你需要用到一个叫做 Vulcanizer 的特殊工具来构建你的 Polymer 元素。而在这个问题上,Vue 可以用异步组件特性配合 Webpack 的代码分割特性,将打包的应用分块,实现懒加载。这既兼容了老式浏览器,又保证了应用加载的性能。 -It is also totally feasible to offer deeper integration between Vue with Web Component specs such as Custom Elements and Shadow DOM style encapsulation - however at this moment we are still waiting for the specs to mature and be widely implemented in all mainstream browsers before making any serious committments. +It is also totally feasible to offer deeper integration between Vue with Web Component specs such as Custom Elements and Shadow DOM style encapsulation - however at this moment we are still waiting for the specs to mature and be widely implemented in all mainstream browsers before making any serious commitments. +Vue 完全可以更深入地和 Web Component 标准融合,比如自定义元素和影子 DOM 这样的封装 - 不过我们会等到这个标准成熟,并且主流浏览器广泛实现这个标准之后,再去认真地投入精力。 ## Riot Riot 2.0 provides a similar component-based development model (which is called a "tag" in Riot), with a minimal and beautifully designed API. Riot and Vue probably share a lot in design philosophies. However, despite being a bit heavier than Riot, Vue does offer some significant advantages: +Riot 2.0 提供了一个跟 Vue 类似的基于组件的开发模型(在 Riot 中被称为 "tag"),而且它还有一个小巧优雅的 API。Riot 和 Vue 在设计思路上又很多相同的地方。虽然 Vue 比 Riot 要更重一些,但 Vue 有一些明显的优势: - True conditional rendering. Riot renders all if branches and simply shows/hides them. +Vue 提供了真正的条件渲染。而 Riot 渲染了所有的条件分支,只是将其它们选择性地显示和隐藏。 - A far more powerful router. Riot’s routing API is extremely minimal. -- More mature tooling support. Vue provides official support for [Webpack](https://github.com/vuejs/vue-loader), [Browserify](https://github.com/vuejs/vueify), and [SystemJS](https://github.com/vuejs/systemjs-plugin-vue), while Riot relies on community support for build system integration. +Vue 有一个更加强大的路由系统。Riot 的路由 API 真的是非常局限。 +- More mature tooling support. Vue provides official support for [Webpack](https://github.com/vuejs/vue-loader) and [Browserify](https://github.com/vuejs/vueify), while Riot relies on community support for build system integration. +Vue 的工具支持更加成熟。它对 [Webpack](https://github.com/vuejs/vue-loader) 和 [Browserify](https://github.com/vuejs/vueify) 提供了官方支持。而 Riot 对构建系统的支持依赖于它的社区。 - [Transition effect system](transitions.html). Riot has none. +Vue 有[过渡效果系统](transitions.html),而 Riot 还没有。 - Better performance. [Despite advertising](https://github.com/vuejs/vuejs.org/issues/346) use of a virtual DOM, Riot in fact uses dirty checking and thus suffers from the same performance issues as Angular 1. +Vue 有更好的性能。尽管 Riot [对外宣称](https://github.com/vuejs/vuejs.org/issues/346) 使用了虚拟 DOM,但它实际上还是使用了脏检查机制,所以跟 Angular 1 有着同样的性能问题。 diff --git a/src/guide/components.md b/src/guide/components.md index 29dfccc1c4..aec4ad42d1 100644 --- a/src/guide/components.md +++ b/src/guide/components.md @@ -1,37 +1,44 @@ --- -title: Components +title: 组件 (Components) type: guide order: 11 --- -## What are Components? +## 组件是什么? (What are Components?) Components are one of the most powerful features of Vue. They help you extend basic HTML elements to encapsulate reusable code. At a high level, components are custom elements that Vue's compiler attaches behavior to. In some cases, they may also appear as a native HTML element extended with the special `is` attribute. +组件是 Vue 最强大的特性之一。组件可以扩展 HTML 元素,封装可复用的代码。从更抽象的层面上讲,组件是自定义元素,而 Vue 编译器将行为绑定到组件上。在某些情况下,组件会以原生 HTML 元素的形式出现,但多了一个特殊的 `is` 属性。 -## Using Components +## 使用组件 (Using Components) -### Registration +### 注册组件 (Registration) -We've learned in the previous sections that we can create a new Vue instances with: +We've learned in the previous sections that we can create a new Vue instance with: +通过先前章节,我们知道可以这样创建一个 Vue 实例: ``` js new Vue({ el: '#some-element', // options + // 选项 }) ``` To register a global component, you can use `Vue.component(tagName, options)`. For example: +可以用 `Vue.component(tagName, options)` 注册一个全局的组件: ``` js Vue.component('my-component', { // options + // 选项 }) ``` -

Note that Vue does not enforce the [W3C rules](http://www.w3.org/TR/custom-elements/#concepts) for custom tag names (all-lowercase, must contain a hyphen) though following this convention is considered good practice.

+

Note that Vue does not enforce the [W3C rules](http://www.w3.org/TR/custom-elements/#concepts) for custom tag names (all-lowercase, must contain a hyphen) though following this convention is considered good practice. +注意,Vue 并不强制要求遵循 [W3C 规则](http://www.w3.org/TR/custom-elements/#concepts) (全小写,必须包含一个短横杠) 来命名标签名,不过遵循这个规则是好的做法。

Once registered, a component can be used in an instance's template as a custom element, ``. Make sure the component is registered **before** you instantiate the root Vue instance. Here's the full example: +一旦组件注册完毕,就可以在模板中以自定义元素 `` 的形式使用了。不过要确保在初始化根实例**之前**注册好组件: ``` html
@@ -41,17 +48,20 @@ Once registered, a component can be used in an instance's template as a custom e ``` js // register +// 注册组件 Vue.component('my-component', { template: '
A custom component!
' }) // create a root instance +// 创建根实例 new Vue({ el: '#example' }) ``` Which will render: +会渲染为: ``` html
@@ -71,9 +81,10 @@ new Vue({ el: '#example' }) {% endraw %} -### Local Registration +### 局部注册 (Local Registration) You don't have to register every component globally. You can make a component available only in the scope of another instance/component by registering it with the `components` instance option: +并不需要全局注册每一个组件,可以让组件只能用在某一个组件或实例内,通过实例选项 `components` 注册: ``` js var Child = { @@ -84,18 +95,22 @@ new Vue({ // ... components: { // will only be available in parent's template + // 只能用在父组件模板内 'my-component': Child } }) ``` The same encapsulation applies for other registerable Vue features, such as directives. +这种封装也适用于其它可注册的 Vue 特性,比如指令(directive)。 -### DOM Template Parsing Caveats +### 模板解析 (DOM Template Parsing Caveats) When using the DOM as your template (e.g. using the `el` option to mount an element with existing content), you will be subject to some restrictions that are inherent to how HTML works, because Vue can only retrieve the template content **after** the browser has parsed and normalized it. Most notably, some elements such as `
    `, `
      `, `` and `
      ` 和 `
      @@ -104,6 +119,7 @@ This will lead to issues when using custom components with elements that have su ``` The custom component `` will be hoisted out as invalid content, thus causing errors in the eventual rendered output. A workaround is to use the `is` special attribute: +`` 组件会被作为空白内容前置,从而导致渲染错误。一个变通方法是加上 `is` 特殊属性: ``` html
      @@ -112,16 +128,21 @@ The custom component `` will be hoisted out as invalid content, thus cau ``` **It should be noted that these limitations do not apply if you are using string templates from one of the following sources**: +**注意,在使用以下来源的模板时没有上述限制**: - ` {% endraw %} -The `el` option also requires a function value when used in a component instance, for exactly the same reason. - -### Composing Components +### 将组件组合使用 (Composing Components) Components are meant to be used together, most commonly in parent-child relationships: component A may use component B in its own template. They inevitably need to communicate to one another: the parent may need to pass data down to the child, and the child may need to inform the parent of something that happened in the child. However, it is also very important to keep the parent and the child as decoupled as possible via a clearly-defined interface. This ensures each component's code can be written and reasoned about in relative isolation, thus making them more maintainable and potentially easier to reuse. +组件本来就是组合使用的,其中特别常见的就是父子关系:组件 A 在自己的模版中使用组件 B。这样,组件间不可避免地需要进行通信:父组件可能需要向下给子组件传递数据,子组件可能需要通知父组件子组件里发生了什么事。不过很重要的一点是,父子组件间要尽可能地通过一个清晰定义的接口来解耦。这样可以确保每个组件的代码都是在相对对立的环境中编写和推理,使得组件更容易维护和复用。 In Vue.js, the parent-child component relationship can be summarized as **props down, events up**. The parent passes data down to the child via **props**, and the child sends messages to the parent via **events**. Let's see how they work next. +在 Vue.js 中,父子组件间的通信可以简单概括为 **通过属性向下通信,通过事件向上通信** 。父组件通过 **props** 向子组件传递数据,子组件通过 **events** 向父组件发送消息。来看一下它们的工作原理:

      props down, events up

      -## Props +## 属性 (Props) -### Passing Data with Props +### 使用属性传递数据 (Passing Data with Props) Every component instance has its own **isolated scope**. This means you cannot (and should not) directly reference parent data in a child component's template. Data can be passed down to child components using **props**. +每个组件实例都有自己 **独立的作用域** ,这意味着你不能并且不该在子组件的模板里直接引用父组件的数据。由父组件向子组件传递数据可以通过 **prop** 来完成。 A prop is a custom attribute for passing information from parent components. A child component needs to explicitly declare the props it expects to receive using the [`props` option](/api/#props): +属性就是用来从父组件传递信息的自定义属性。子组件需要显式地用 [`props` 选项](/api/#props) 来明确声明它要接收的属性: ``` js Vue.component('child', { // declare the props + // 声明 props props: ['message'], // just like data, the prop can be used inside templates // and is also made available in the vm as this.message + // message 属性可以像数据对象的属性一样在模板里使用 + // 也可以在 vm 里通过 this.message 来访问 template: '{{ message }}' }) ``` Then we can pass a plain string to it like so: +然后可以像这样传入一个字符串: ``` html ``` Result: +结果: {% raw %}
      @@ -268,13 +301,15 @@ new Vue({ {% endraw %} -### camelCase vs. kebab-case +### 驼峰命名与短横分隔命名 (camelCase vs. kebab-case) HTML attributes are case-insensitive, so when using non-string templates, camelCased prop names need to use their kebab-case (hyphen-delimited) equivalents: +HTML 属性不区分大小写,所以当使用非字符串模版时,你需要使用短横分隔命名的名字,来对应驼峰命名的属性名: ``` js Vue.component('child', { // camelCase in JavaScript + // JavaScript 的驼峰命名 props: ['myMessage'], template: '{{ myMessage }}' }) @@ -282,14 +317,17 @@ Vue.component('child', { ``` html + ``` Again, if you're using string templates, then this limitation does not apply. +再强调一次,使用字符串模板的时候没有这些限制。 -### Dynamic Props +### 动态属性 (Dynamic Props) Similar to binding a normal attribute to an expression, we can also use `v-bind` for dynamically binding props to data on the parent. Whenever the data is updated in the parent, it will also flow down to the child: +类似于将普通的 HTML 元素绑定到一个表达式,我们也可以用 `v-bind` 将组件的属性绑定到父组件的数据。这样父组件的数据发生变化时,就会传递给子组件: ``` html
      @@ -300,12 +338,14 @@ Similar to binding a normal attribute to an expression, we can also use `v-bind` ``` It's often simpler to use the shorthand syntax for `v-bind`: +使用 `v-bind` 的缩写语法会更简单: ``` html ``` Result: +结果: {% raw %}
      @@ -329,67 +369,87 @@ new Vue({ {% endraw %} -### Literal vs Dynamic +### 字面量语法 vs 动态语法 (Literal vs Dynamic) A common mistake beginners tend to make is attempting to pass down a number using the literal syntax: +初学者容易犯的一个常见错误就是使用字面量语法传递数值: ``` html + ``` However, since this is a literal prop, its value is passed down as a plain string `"1"` instead of an actual number. If we want to pass down an actual JavaScript number, we need to use `v-bind` so that its value is evaluated as a JavaScript expression: +然而,因为这是一个字面属性,它的值以字符串 `"1"` 的形式传递,而不是一个数值。如果想要传递真正的 JavaScript 数值,需要使用 `v-bind` 这种动态语法,从而让值被当做 JavaScript 表达式计算: ``` html + ``` -### One-Way Data Flow +### 单向数据流 (One-Way Data Flow) All props form a **one-way-down** binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent's state, which can make your app's data flow harder to reason about. +所有的属性都是 **单向** 绑定的:父组件的属性变化时,会传递到子组件,但并不会反向传递。这就避免了子组件不小心改变父组件状态的情况,让应用的数据流更容易推理。 In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should **not** attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console. +而且,每次更新父组件,子组件的所有属性值都会被更新成最新值,因此 **不** 应该在子组件内改变属性的值,如果你这样做的话,Vue 会在控制台抛出警告。 There are usually two cases where it's tempting to mutate a prop: +通常有这两种场景你可能会想要直接改变属性值: 1. The prop is used to only pass in an initial value, the child component simply wants to use it as a local data property afterwards; +属性只是用来传递初始值,实际上子组件将它作为本地数据属性来使用; 2. The prop is passed in as a raw value that needs to be transformed. +属性作为原始值被传递进来,它需要经过变形来进一步使用。 The proper answer to these use cases are: +这些场景的正确解决方式时: 1. Define a local data property that uses the prop's initial value as its initial value; +定义一个本地数据属性,它的初始值就是属性的初始值; 2. Define a computed property that is computed from the prop's value. +定义一个用基于属性值计算的计算属性。 -

      Note that objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or array itself inside the child **will** affect parent state.

      +

      Note that objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or array itself inside the child **will** affect parent state. +要注意,在 JavaScript 中对象和数组时通过引用传递的。如果属性是数组活着对象,在子组件内修改 **会** 影响父组件的状态。

      -### Prop Validation +### 属性校验 (Prop Validation) It is possible for a component to specify requirements for the props it is receiving. If a requirement is not met, Vue will emit warnings. This is especially useful when you are authoring a component that is intended to be used by others. +组件可以为属性指定校验要求。如果没有满足要求,Vue 会抛出警告。如果组件给其他人使用的,那组件校验就会非常有用。 Instead of defining the props as an array of strings, you can use an object with validation requirements: +属性除了可以定义为字符串数组,也可以定义为包含验证条件的对象: ``` js Vue.component('example', { props: { // basic type check (`null` means accept any type) + // 基本类型验证(`null` 意思是任何类型都可以) propA: Number, // multiple possible types + // 多种类型 propB: [String, Number], // a required string + // 一个必需的字符串属性 propC: { type: String, required: true }, // a number with default value + // 数值属性,有默认值 propD: { type: Number, default: 100 }, // object/array defaults should be returned from a // factory function + // 对象/数组的默认值应由函数返回 propE: { type: Object, default: function () { @@ -397,6 +457,7 @@ Vue.component('example', { } }, // custom validator function + // 自定义验证函数 propF: { validator: function (value) { return value > 10 @@ -407,6 +468,7 @@ Vue.component('example', { ``` The `type` can be one of the following native constructors: +`type` 可以是以下原生构造器: - String - Number @@ -416,23 +478,34 @@ The `type` can be one of the following native constructors: - Array In addition, `type` can also be a custom constructor function and the assertion will be made with an `instanceof` check. +`type` 也可以是自定义的构造函数,使用 `instanceof` 校验。 -When a prop validation fails, Vue will refuse to set the value on the child component and throw a warning if using the development build. +When a prop validation fails, Vue will produce a console warning (if using the development build). +如果属性校验失败,Vue 会抛出控制台警告(如果使用的是开发版本)。 -## Custom Events +## 自定义事件 (Custom Events) -We have learned that the parent can pass data down to the child using props, but how do we communicate back to the parent when something happens? This is where custom events come in. +We have learned that the parent can pass data down to the child using props, but how do we communicate back to the parent when something happens? This is where Vue's custom event system comes in. +在之前章节已经知道,父组件可以使用属性传递数据到子组件,但是反过来子组件向父组件通信该怎么做呢?是时候让 Vue 的自定义事件系统上场了。 -### Using `v-on` with Custom Events +### 使用 `v-on` 绑定自定义事件 (Using `v-on` with Custom Events) -Every Vue instance implements the [Events interface](/api/#Instance-Methods-Events), which means it can: +Every Vue instance implements an [events interface](/api/#Instance-Methods-Events), which means it can: +Vue 实例实现了 [事件接口](/api/#Instance-Methods-Events),这意味着它可以: - Listen to an event using `$on(eventName)` +通过 `$on(eventName)` 监听事件 - Trigger an event using `$emit(eventName)` +通过 `$emit(eventName)` 触发事件 + +

      Note that Vue's event system is separate from the browser's [EventTarget API](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget). Though they work similarly, `$on` and `$emit` are __not__ aliases for `addEventListener` and `dispatchEvent`. +要注意,Vue 的事件系统跟浏览器的 [EventTarget API](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) 是两回事,虽然它们的工作方式类似。`$on` 和 `$emit` __并不是__ `addEventListener` 和 `dispatchEvent` 的别名。

      In addition, a parent component can listen to the events emitted from a child component using `v-on` directly in the template where the child component is used. +除此之外,父组件也可以在模版中直接使用 `v-on`,来监听子组件分发的事件。 Here's an example: +如下例: ``` html
      @@ -507,41 +580,51 @@ new Vue({ {% endraw %} In this example, it's important to note that the child component is still completely decoupled from what happens outside of it. All it does is report information about its own activity, just in case a parent component might care. +值得注意的一点是,在这个例子中,子组件与它的外部仍然是解耦的,子组件只是根据它的内部活动,向父组件报告信息,而不管父组件如何处理。 -#### Binding Native Events to Components +#### 在组件上绑定原生事件 (Binding Native Events to Components) There may be times when you want to listen for a native event on the root element of a component. In these cases, you can use the `.native` modifier for `v-on`. For example: +你可能经常需要在组件的根元素上监听原生事件,这种情况下可以在 `v-on` 上添加一个 `.native` 修饰器,比如: ``` html ``` -### Form Input Components using Custom Events +### 在表单控件上使用自定义事件 (Form Input Components using Custom Events) This strategy can also be used to create custom form inputs that work with `v-model`. Remember: +这个策略也可以用来创建自定义的表单控件,它依然可以使用 v-model。要记住: ``` html ``` is just syntactic sugar for: +只是下面这段代码的语法糖: ``` html ``` When used with a component, this simplifies to: +与组件一起使用时就会简化为: ``` html ``` So for a component to work with `v-model`, it must: +因此,要使用 `v-model`,组件必须满足如下条件: - accept a `value` prop +接收一个 `value` 属性 + - emit an `input` event with the new value +有新的 value 值时分发一个 `input` 事件 Let's see it in action: +看一下实际应用: ``` html
      @@ -620,6 +703,7 @@ new Vue({ {% endraw %} This interface can be used not only to connect with form inputs inside a component, but also to easily integrate input types that you invent yourself. Imagine these possibilities: +这个接口不仅可以连接组件内的表单控件,还可以轻松整合自定义的输入类型。想一下以下可能性: ``` html @@ -627,29 +711,34 @@ This interface can be used not only to connect with form inputs inside a compone ``` -### Non Parent-Child Communication +### 非父子组件通信 (Non Parent-Child Communication) Sometimes two components may need to communicate with one-another but they are not parent/child to each other. In simple scenarios, you can use an empty Vue instance as a central event bus: +有时候两个非父子关系的组件也需要通信。情景简单的话可以把一个空的 Vue 实例作为事件中心: ``` js var bus = new Vue() ``` ``` js // in component A's method +// 在组件 A 的方法中 bus.$emit('id-selected', 1) ``` ``` js // in component B's created hook +// 在组件 B 的 created 钩子中 bus.$on('id-selected', function (id) { // ... }) ``` In more complex cases, you should consider employing a dedicated [state-management pattern](/guide/state-management.html). +如果是更复杂的场景,就要考虑引入专用的 [状态管理模式](/guide/state-management.html)了。 -## Content Distribution with Slots +## 使用插槽分发内容 (Content Distribution with Slots) When using components, it is often desired to compose them like this: +使用组件时,常常要像这样组合它们: ``` html @@ -659,16 +748,21 @@ When using components, it is often desired to compose them like this: ``` There are two things to note here: +注意两点: 1. The `` component does not know what content may be present inside its mount target. It is decided by whatever parent component that is using ``. +`` 组件并不知道它的挂载点会有什么内容,这取决于 `` 的父组件。 2. The `` component very likely has its own template. +`` 组件很可能有它自己的模板。 To make the composition work, we need a way to interweave the parent "content" and the component's own template. This is a process called **content distribution** (or "transclusion" if you are familiar with Angular). Vue.js implements a content distribution API that is modeled after the current [Web Components spec draft](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md), using the special `` element to serve as distribution outlets for the original content. +为了让组件可以组合使用,我们需要一种方式混合父组件的内容和子组件自己的模板。 我们将这个过程称为 **内容分发** (类似 Angular 中的 “transclusion”)。 Vue.js 参照当前的 [Web 组件规范草案](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md),实现了一个内容分发的 API,使用特殊的 `` 元素作为原始内容的插槽。 -### Compilation Scope +### 编译作用域 (Compilation Scope) Before we dig into the API, let's first clarify which scope the contents are compiled in. Imagine a template like this: +在深入 API 之前,需要先搞清楚内容的编译作用域。假定模板为: ``` html @@ -677,23 +771,30 @@ Before we dig into the API, let's first clarify which scope the contents are com ``` Should the `message` be bound to the parent's data or the child data? The answer is the parent. A simple rule of thumb for component scope is: +`messgae` 应该绑定在父组件还是子组件的数据里?答案是父组件。组件作用域有一个简单的规则: > Everything in the parent template is compiled in parent scope; everything in the child template is compiled in child scope. +> 父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。 A common mistake is trying to bind a directive to a child property/method in the parent template: +一个常见错误是试图在父组件模板内把指令绑定到子组件的属性/方法: ``` html + ``` Assuming `someChildProperty` is a property on the child component, the example above would not work. The parent's template is not aware of the state of a child component. +假设 `someChildProperty` 是子组件的属性,上例不会如预期一样运行。父组件并不清楚子组件的状态。 If you need to bind child-scope directives on a component root node, you should do so in the child component's own template: +在组件的根节点内,如果你需要绑定子组件的指令,那么你应该在子组件自己的模版里这样做: ``` js Vue.component('child-component', { // this does work, because we are in the right scope + // 有效,因为是在正确的作用域内 template: '
      Child
      ', data: function () { return { @@ -704,14 +805,18 @@ Vue.component('child-component', { ``` Similarly, distributed content will be compiled in the parent scope. +同样,分发内容会在父组件的作用域内编译。 -### Single Slot +### 单个插槽 (Single Slot) Parent content will be **discarded** unless the child component template contains at least one `` outlet. When there is only one slot with no attributes, the entire content fragment will be inserted at its position in the DOM, replacing the slot itself. +除非子组件内包含 `` ,否则父组件的内容将被 **丢弃**。如果子组件内只有一个没有属性的插槽,父组件的所有内容都会被插入到插槽在 DOM 中的位置,替换掉插槽本身。 Anything originally inside the `` tags is considered **fallback content**. Fallback content is compiled in the child scope and will only be displayed if the hosting element is empty and has no content to be inserted. +`` 标签内的内容视为 **替换内容**。替换内容在子组件作用域内编译,并且只在宿主元素为空或没有内容供插入时才显示这个替换内容。 Suppose we have a component called `my-component` with the following template: +假定 `my-component` 组件有以下模板: ``` html
      @@ -724,6 +829,7 @@ Suppose we have a component called `my-component` with the following template: ``` And a parent that uses the component: +父组件模板: ``` html
      @@ -736,6 +842,7 @@ And a parent that uses the component: ``` The rendered result will be: +渲染结果: ``` html
      @@ -748,13 +855,16 @@ The rendered result will be:
      ``` -### Named Slots +### 具名插槽 (Named Slots) `` elements have a special attribute, `name`, which can be used to further customize how content should be distributed. You can have multiple slots with different names. A named slot will match any element that has a corresponding `slot` attribute in the content fragment. +`` 元素有一个特殊的属性 `name`,可以用来自定义内容分发的方式。你可以有多个不同名字的插槽。具名插槽会匹配内容片断中有相应 `slot` 属性的元素。 There can still be one unnamed slot, which is the **default slot** that serves as a catch-all outlet for any unmatched content. If there is no default slot, unmatched content will be discarded. +你仍然可以使用一个匿名插槽来作为 **默认插槽**,它可以捕捉所有匹配不到的内容片段。如果没有默认插槽的话,那些无法匹配的内容片段将被丢弃。 For example, suppose we have an `app-layout` component with the following template: +举个例子,假定 `app-layout` 有以下模板: ``` html
      @@ -771,6 +881,7 @@ For example, suppose we have an `app-layout` component with the following templa ``` Parent markup: +父组件模板: ``` html @@ -784,6 +895,7 @@ Parent markup: ``` The rendered result will be: +渲染结果为: ``` html
      @@ -801,10 +913,12 @@ The rendered result will be: ``` The content distribution API is a very useful mechanism when designing components that are meant to be composed together. +设计组合使用的组件时,内容分发 API 是非常有用的机制。 -## Dynamic Components +## 动态组件 (Dynamic Components) You can use the same mount point and dynamically switch between multiple components using the reserved `` element and dynamically bind to its `is` attribute: +多个组件可以使用同一挂载点并且动态切换,只需要使用保留的 `` 元素,绑定它的 `is` 属性: ``` js var vm = new Vue({ @@ -823,10 +937,12 @@ var vm = new Vue({ ``` html + ``` If you prefer, you can also bind directly to component objects: +也可以直接绑定到组件对象: ``` js var Home = { @@ -844,32 +960,41 @@ var vm = new Vue({ ### `keep-alive` If you want to keep the switched-out components in memory so that you can preserve their state or avoid re-rendering, you can wrap a dynamic component in a `` element: +如果把切换出去的组件保留在内存中,以保留它的状态或避免重新渲染,可以用 `` 元素包装动态组件: ``` html + ``` Check out more details on `` in the [API reference](/api/#keep-alive). +更多细节请参考 [api 手册](/api/#keep-alive) 中的 `` 部分。 -## Misc +## 杂项 (Misc) -### Authoring Reusable Components +### 编写可复用组件 (Authoring Reusable Components) When authoring components, it's good to keep in mind whether you intend to reuse it somewhere else later. It's OK for one-off components to be tightly coupled, but reusable components should define a clean public interface and make no assumptions about the context it's used in. +编写组件时,要想清楚是否要复用组件。一次性组件跟其它组件紧密耦合是可以接受的,但是需要复用的组件应当定义一个清晰的公共接口,不要妄自假设组件所被使用的上下文环境。 The API for a Vue component comes in three parts - props, events, and slots: +Vue 组件的 API 来自于属性,事件和插槽三部分: - **Props** allow the external environment to pass data into the component +外部环境通过**属性**将数据传递给组件; - **Events** allow the component to trigger side effects in the external environment +组件通过**事件**对外部环境产生影响; - **Slots** allow the external environment to compose the component with extra content. +外部环境通过**插槽**将外部内容和组件组合在一起。 With the dedicated shorthand syntaxes for `v-bind` and `v-on`, the intents can be clearly and succinctly conveyed in the template: +使用 `v-bind` 和 `v-on` 的简写语法,在模版中可以更清晰简洁地传达意图: ``` html ``` -### Child Component Refs +### 子组件索引 (Child Component Refs) Despite the existence of props and events, sometimes you might still need to directly access a child component in JavaScript. To achieve this you have to assign a reference ID to the child component using `ref`. For example: +尽管有属性和事件,但是有时仍然需要在 JavaScript 中直接访问子组件。为此可以使用 `v-ref` 为子组件分配一个引用 ID : ``` html
      @@ -896,16 +1022,20 @@ Despite the existence of props and events, sometimes you might still need to dir ``` js var parent = new Vue({ el: '#parent' }) // access child component instance +// 访问子组件 var child = parent.$refs.profile ``` When `ref` is used together with `v-for`, the ref you get will be an array or an object containing the child components mirroring the data source. +`ref` 与 `v-for` 一起使用时 ref 是一个数组或对象,包含相应的子组件。 -

      `$refs` are only populated after the component has been rendered, and it is not reactive. It is only meant as an escape hatch for direct child manipulation - you should avoid using `$refs` in templates or computed properties.

      +

      `$refs` are only populated after the component has been rendered, and it is not reactive. It is only meant as an escape hatch for direct child manipulation - you should avoid using `$refs` in templates or computed properties. +`$refs` 在组件渲染完成后才会被填充,而且它不是响应式的。它仅仅是一个直接操作子组件的应急手段,你应该避免在模板或计算属性中使用 `$refs`。

      -### Async Components +### 异步组件 (Async Components) In large applications, we may need to divide the app into smaller chunks and only load a component from the server when it's actually needed. To make that easier, Vue allows you to define your component as a factory function that asynchronously resolves your component definition. Vue will only trigger the factory function when the component actually needs to be rendered and will cache the result for future re-renders. For example: +在大型应用中,我们可能需要将应用拆分为小块,只在需要时才从服务器下载。为了让事情更简单,Vue 允许把组件定义为一个工厂函数,异步地解析组件的定义。Vue 只在组件需要渲染时触发工厂函数,并且把结果缓存起来,用于后面的再次渲染。例如: ``` js Vue.component('async-example', function (resolve, reject) { @@ -918,17 +1048,21 @@ Vue.component('async-example', function (resolve, reject) { ``` The factory function receives a `resolve` callback, which should be called when you have retrieved your component definition from the server. You can also call `reject(reason)` to indicate the load has failed. The `setTimeout` here is simply for demonstration; How to retrieve the component is entirely up to you. One recommended approach is to use async components together with [Webpack's code-splitting feature](http://webpack.github.io/docs/code-splitting.html): +工厂函数接收一个 `resolve` 回调,在收到从服务器下载的组件定义时调用。也可以在加载失败时调用 `reject(reason)` 。 这里的 `setTimeout` 只是为了演示;获取组件的方式完全取决于你。推荐配合 [Webpack 的代码分割功能](http://webpack.github.io/docs/code-splitting.html) 来使用异步组件: ``` js Vue.component('async-webpack-example', function (resolve) { // This special require syntax will instruct Webpack to // automatically split your built code into bundles which // are loaded over Ajax requests. + // 这个特殊的 require 语法告诉 webpack 自动将编译后的代码分割成不同的块, + // 这些块将通过 ajax 请求自动下载。 require(['./my-async-component'], resolve) }) ``` You can also return a `Promise` in the resolve function, so with Webpack 2 + ES2015 syntax you can do: +也可以在 resolve 函数中返回一个 `Promise` 对象,在 Webpack 2 与 ES2015 语法配合下你可以这样: ``` js Vue.component( @@ -937,14 +1071,20 @@ Vue.component( ) ``` -### Component Naming Conventions +

      If you're a Browserify user that would like to use async components, it's unfortunately not possible and probably never will be, as its creator has [made it clear](https://github.com/substack/node-browserify/issues/58#issuecomment-21978224) that async loading "is not something that Browserify will ever support." If this is a feature that's important to you, we recommend using Webpack instead. +如果你时 Browserify 用户,想要使用异步组件,很抱歉你的愿望可能永远都实现不了。因为它的作者已经[明确地说](https://github.com/substack/node-browserify/issues/58#issuecomment-21978224),“Browserify 永远都不会支持”异步加载。如果这个特性对你很重要,那么我们推荐你使用 Webpack。

      + +### 组件命名约定 (Component Naming Conventions) When registering components (or props), you can use kebab-case, camelCase, or TitleCase. Vue doesn't care. +当你注册组件(或者属性)时,Vue 并不关心你用的到底是驼峰命名,短横分隔命名,还是标题命名: ``` js // in a component definition +// 在组件定义中 components: { // register using camelCase + // 使用驼峰命名注册组件 'kebab-cased-component': { /* ... */ }, 'camelCasedComponent': { /* ... */ }, 'TitleCasedComponent': { /* ... */ } @@ -952,58 +1092,87 @@ components: { ``` Within HTML templates though, you have to use the kebab-case equivalents: +在 HTML 模板中必须使用短横分隔命名: ``` html + ``` When using _string_ templates however, we're not bound by HTML's case-insensitive restrictions. That means even in the template, you reference your components and props using camelCase, PascalCase, or kebab-case: +使用 __字符串__ 模版时,我们不受 HTML 的大小写限制。所以在模版中,你可以用使用驼峰命名,短横分隔命名以及标题命名的任意一种: ``` html + ``` If your component isn't passed content via `slot` elements, you can even make it self-closing with a `/` after the name: +如果组件没有用 `slot` 元素传递内容,也可以把 `/` 直接添加到组件名后面,使组件自闭合: ``` html ``` Again, this _only_ works within string templates, as self-closing custom elements are not valid HTML and your browser's native parser will not understand them. +再次重申,这种模式 _只_ 适用于字符串模板,浏览器的原生解析器无法理解自闭合的元素,它们是无效的 HTML 。 -### Recursive Component +### 递归组件 (Recursive Component) Components can recursively invoke themselves in their own template. However, they can only do so with the `name` option: +组件在它的模板内可以递归地调用自己,不过,只有当它有 `name` 选项时才可以: + +``` js +name: 'unique-name-of-my-component' +``` + +When you register a component globally using `Vue.component`, the global ID is automatically set as the component's `name` option. +当你用 `Vue.component` 全局注册组件时,组件的全局 ID 会自动设置为组件的 `name` 选项。 + +``` js +Vue.component('unique-name-of-my-component', { + // ... +}) +``` + +If you're not careful, recursive components can also lead to infinite loops: +如果不小心的话,递归组件也可能导致无限循环: ``` js name: 'stack-overflow', template: '
      ' ``` -A component like the above will result in a "max stack size exceeded" error, so make sure recursive invocation is conditional (i.e. uses a `v-if` that will eventually be false). When you register a component globally using `Vue.component`, the global ID is automatically set as the component's `name` option. +A component like the above will result in a "max stack size exceeded" error, so make sure recursive invocation is conditional (i.e. uses a `v-if` that will eventually be `false`). +上面组件会导致一个错误 “max stack size exceeded”,所以要确保递归调用有终止条件(比如使用一个最终会为 `false` 的 `v-if` 指令)。 -### Inline Templates +### 内联模板 (Inline Templates) When the `inline-template` special attribute is present on a child component, the component will use its inner content as its template, rather than treating it as distributed content. This allows more flexible template-authoring. +如果子组件有 `inline-template` 特殊属性,组件将把它的内容当作它的模板,而不是把它当作分发内容。这让你可以很灵活地编写模版。 ``` html -

      These are compiled as the component's own template.

      -

      Not parent's transclusion content.

      +
      +

      These are compiled as the component's own template.

      +

      Not parent's transclusion content.

      +
      ``` However, `inline-template` makes the scope of your templates harder to reason about. As a best practice, prefer defining templates inside the component using the `template` option or in a `template` element in a `.vue` file. +但是 `inline-template` 让模板的作用域难以理解。最佳实践是通过 `template` 选项在组件内定义模版,或者在 `.vue` 文件中的 `template` 元素内定义模板。 -### X-Templates +### X-Templates (X-Templates) Another way to define templates is inside of a script element with the type `text/x-template`, then referencing the template by an id. For example: +另一种定义模板的方法,是在类型为 `text/x-template` 的 script 元素里定义模版,然后在 id 引用 这个模版。比如: ``` html {% endraw %} -## Function Shorthand +## 简略的写法 (Function Shorthand) In many cases, you may want the same behavior on `bind` and `update`, but don't care about the other hooks. For example: +如果指令只需要处理`bind`和`update`事件,可以简写为如下形式: ``` js Vue.directive('color-swatch', function (el, binding) { @@ -148,9 +188,10 @@ Vue.directive('color-swatch', function (el, binding) { }) ``` -## Object Literals +## 对象字面量 (Object Literals) If your directive needs multiple values, you can also pass in a JavaScript object literal. Remember, directives can take any valid JavaScript expression. +如果指令需要多个值,可以传入一个 JavaScript 对象字面量,亦可以是任何有效的 JavaScript 表达式。 ``` html
      diff --git a/src/guide/deployment.md b/src/guide/deployment.md new file mode 100644 index 0000000000..926bfc53d0 --- /dev/null +++ b/src/guide/deployment.md @@ -0,0 +1,67 @@ +--- +title: 生产环境部署 (Deploying For Production) +type: guide +order: 20 +--- + +## 去除警告 (Stripping Out Warnings) + +The minified standalone build of Vue has already stripped out all the warnings for you for a smaller file size, but when you are using tools like Webpack or Browserify, you will need some additional configuration to achieve this. +为了缩减文件大小,Vue 的最小化独立版本已经去除了所有警告。不过,如果你在使用 Webpack 或 Browserify 这样的工具,那就需要做一些额外的配置。 + +### Webpack + +Use Webpack's [DefinePlugin](http://webpack.github.io/docs/list-of-plugins.html#defineplugin) to indicate a production environment, so that warning blocks can be automatically dropped by UglifyJS during minification. Example config: +用 Webpack 的 [DefinePlugin](http://webpack.github.io/docs/list-of-plugins.html#defineplugin) 来表明你处于生产环境,这样 UglifyJS 就会在压缩阶段自动去除警告块。配置的示例如下: + +``` js +var webpack = require('webpack') + +module.exports = { + // ... + plugins: [ + // ... + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: '"production"' + } + }), + new webpack.optimize.UglifyJsPlugin({ + compress: { + warnings: false + } + }) + ] +} +``` + +### Browserify + +- Run your bundling command with `NODE_ENV` set to `"production"`. This tells `vueify` to avoid including hot-reload and development related code. +将 `NODE_ENV` 设成 `"production"`,然后运行打包命令。这会让 `vueify` 不打包热重载和开发相关的代码。 + +- Apply a global [envify](https://github.com/hughsk/envify) transform to your bundle. This allows the minifier to strip out all the warnings in Vue's source code wrapped in env variable conditional blocks. For example: +用 [envify](https://github.com/hughsk/envify) 对你的打包文件进行全局转换。这会让简化工具检查 Vue 源代码中的环境变量分支块,去除其中的所有警告。比如: +``` bash +NODE_ENV=production browserify -g envify -e main.js | uglifyjs -c -m > build.js +``` + +- To extract styles to a separate css file use a extract-css plugin which is included in vueify. +用包含在 vueify 中的 extract-css 插件,将样式提取到独立的 CSS 文件。 + +``` bash +NODE_ENV=production browserify -g envify -p [ vueify/plugins/extract-css -o build.css ] -e main.js | uglifyjs -c -m > build.js +``` + +## 追踪运行时错误 (Tracking Runtime Errors) + +If a runtime error occurs during a component's render, it will be passed to the global `Vue.config.errorHandler` config function if it has been set. It might be a good idea to leverage this hook together with an error-tracking service like [Sentry](https://sentry.io), which provides [an official integration](https://sentry.io/for/vue/) for Vue. +如果在组件渲染期间发生了运行时错误,这个错误会被传递到全局的 `Vue.config.errorHandler` 配置函数(如果已设置)。一个很好的做法是,将这个钩子函数和错误追踪服务(比如 [Sentry](https://sentry.io))组合使用,Sentry 甚至还为 Vue 提供了 [一个官方插件](https://sentry.io/for/vue/)。 + +## 提取 CSS (Extracting CSS) + +When using [Single-File Components](./single-file-components.html), the ` {% endraw %} -## Dynamic State Transitions +## 动态的状态过渡效果 (Dynamic State Transitions) Just as with Vue's transition components, the data backing state transitions can be updated in real time, which is especially useful for prototyping! Even using a simple SVG polygon, you can achieve many effects that would be difficult to conceive of until you've played with the variables a little. +就像 Vue 的过渡效果组件一样,状态过渡效果背后的数据也是可以实时更新的,这对于原型设计十分有用!当你能够随意调整变量时,即使是一个简单的 SVG 多边形也可以实现很多难以想象的效果。 {% raw %} @@ -375,10 +387,12 @@ function generatePoints (stats) { {% endraw %} See [this fiddle](https://jsfiddle.net/chrisvfritz/65gLu2b6/) for the complete code behind the above demo. +这个演示的完整代码可以参考 [这里](https://jsfiddle.net/chrisvfritz/65gLu2b6/)。 -## Organizing Transitions into Components +## 用组件管理过渡效果 (Organizing Transitions into Components) Managing many state transitions can quickly increase the complexity of a Vue instance or component. Fortunately, many animations can be extracted out into dedicated child components. Let's do this with the animated integer from our earlier example: +管理多个状态过渡效果会让 Vue 实例或组件的复杂度快速增加。幸好,很多动效都可以提取到专门的子组件。让我们改写一下之前的示例代码: ``` html @@ -401,6 +415,10 @@ Managing many state transitions can quickly increase the complexity of a Vue ins // Components also offer a clean interface for configuring // more dynamic transitions and complex transition // strategies. +// 这种复杂的补间动画逻辑可以被复用 +// 任何整数都可以执行动画 +// 组件化使我们的界面十分清晰 +// 可以支持更多更复杂的动态过渡策略 Vue.component('animated-integer', { template: '{{ tweeningValue }}', props: { @@ -441,6 +459,7 @@ Vue.component('animated-integer', { }) // All complexity has now been removed from the main Vue instance! +// 我们把这些复杂度从主 Vue 实例中移除了! new Vue({ el: '#example-8', data: { @@ -522,3 +541,4 @@ new Vue({ {% endraw %} Within child components, we can use any combination of transition strategies that have been covered on this page, along with those offered by Vue's [built-in transition system](transitions.html). Together, there are very few limits to what can be accomplished. +在子组件中,我们可以任意组合之前提到的各种过渡效果策略,以及 Vue [内置过渡效果系统](transitions.html)提供的策略。把它们组合起来使用,几乎可以实现任何过渡效果。 \ No newline at end of file diff --git a/src/guide/transitions.md b/src/guide/transitions.md index 2447f7d855..b7b7bf6abf 100644 --- a/src/guide/transitions.md +++ b/src/guide/transitions.md @@ -1,30 +1,42 @@ --- -title: 'Transitions: Entering, Leaving, and Lists' +title: 过渡效果 (Transition Effects) type: guide -order: 12 +order: 13 --- -## Overview +## 概况 (Overview) Vue provides a variety of ways to apply transition effects when items are inserted, updated, or removed from the DOM. This includes tools to: +Vue 为插入元素,更新元素,以及从 DOM 中移除元素提供了多种过渡效果。包括以下工具: - automatically apply classes for CSS transitions and animations +自动应用 CSS 过渡效果和动画的类 - integrate 3rd-party CSS animation libraries, such as Animate.css +整合第三方 CSS 动画库如 Animate.css - use JavaScript to directly manipulate the DOM during transition hooks +在过渡效果的钩子中使用 JavaScript 直接控制 DOM - integrate 3rd-party JavaScript animation libraries, such as Velocity.js +整合第三方 JavaScript 动画库例如 Velocity.js On this page, we'll only cover entering, leaving, and list transitions, but you can see the next section for [managing state transitions](transitioning-state.html). +本节教程只会涉及进入、离开和列表的过渡效果,关于如何[管理状态的过渡](transitioning-state.html),你可以阅读下一节。 -## Transitioning Single Elements/Components +## 单一元素/组件过渡 (Transitioning Single Elements/Components) Vue provides a `transition` wrapper component, allowing you to add entering/leaving transitions for any element or component in the following contexts: +Vue 提供一个 `transition` 包裹组件,使你能够在下列情况中,为任意元素或组件添加进入或离开的过渡效果: - Conditional rendering (using `v-if`) +条件渲染(使用 `v-if`) - Conditional display (using `v-show`) +条件展示(使用 `v-show`) - Dynamic components +动态组件 - Component root nodes +组件根节点 This is what a very simple example looks like in action: +这是实际应用中的一个简单的例子: ``` html
      @@ -83,31 +95,41 @@ new Vue({ {% endraw %} When an element wrapped in a `transition` component is inserted or removed, this is what happens: +当被包裹在 `transition` 中的元素插入 DOM,或从 DOM 中移除时,Vue 将: 1. Vue will automatically sniff whether the target element has CSS transitions or animations applied. If it does, CSS transition classes will be added/removed at appropriate timings. +自动嗅探目标元素是否应用了 CSS 过渡或动画。如果有,将会在合适时添加/删除 CSS 过渡的类; 2. If the transition component provided [JavaScript hooks](#JavaScript-Hooks), these hooks will be called at appropriate timings. +如果过渡组件提供了 [JavaScript 钩子](#JavaScript-Hooks),这些钩子函数将会在适当的时候被调用; 3. If no CSS transitions/animations are detected and no JavaScript hooks are provided, the DOM operations for insertion and/or removal will be executed immediately on next frame (Note: this is a browser animation frame, different from Vue's concept of `nextTick`). +如果既没有检测到 CSS 过渡/动画也没有提供 JavaScript 钩子,DOM 操作(插入/删除)将会在下一帧中立即执行。(注意:这里的帧指浏览器动画帧,与 Vue 中 `nextTick` 的概念不同) -### Transition Classes +### 过渡类名 (Transition Classes) There are four classes applied for enter/leave transitions. +进入/离开的过渡将会使用到下列四个类名: 1. `v-enter`: Starting state for enter. Applied before element is inserted, removed after one frame. +`v-enter`:进入过渡的开始状态。在元素被插入前或元素移除后的下一帧应用; 2. `v-enter-active`: Active and ending state for enter. Applied before element is inserted, removed when transition/animation finishes. +`v-enter-active`:进入过渡的活跃和结束状态。在元素被插入前应用,当过渡/动画结束时被删除; 3. `v-leave`: Starting state for leave. Applied when leave transition is triggered, removed after one frame. +`v-leave`:离开过渡的开始状态。当离开过渡开始时生效,只应用一帧然后立即被删除; 4. `v-leave-active`: Active and ending state for leave. Applied when leave transition is triggered, removed when the transition/animation finishes. - -![Transition Diagram](/images/transition.png) +`v-leave-active`:离开过渡的活跃和结束状态。当离开过渡开始时生效,当过渡/动画结束后立即被删除。 Each of these classes will be prefixed with the name of the transition. Here the `v-` prefix is the default when you use a `` element with no name. If you use `` for example, then the `v-enter` class would instead be `my-transition-enter`. +每一个类的前缀都是对应的过渡的 name 是以上类名的前缀。当 `` 没有 name 时,则默认为这里的 `v-` 前缀。如果你使用 `` , `v-enter` 类名应该改为 `my-transition-enter`。 `v-enter-active` and `v-leave-active` give you the ability to specify different easing curves for enter/leave transitions, which you'll see an example of in the following section. +`v-enter-active` 和 `v-leave-active` 将使你能够为进入/离开过渡效果声明不同的缓冲曲线,你将能在下一节看到例子。 -### CSS Transitions +### CSS 过渡 (CSS Transitions) One of the most common transition types uses CSS transitions. Here's a simple example: +CSS 过渡是最常用的一种过渡类型。例如: ``` html
      @@ -132,6 +154,7 @@ new Vue({ ``` css /* Enter and leave animations can use different */ /* durations and timing functions. */ +/* 进入和离开的动画可以使用不同的 duration 和 timing 函数 */ .slide-fade-enter-active { transition: all .3s ease; } @@ -175,11 +198,13 @@ new Vue({ {% endraw %} -### CSS Animations +### CSS 动画 (CSS Animations) CSS animations are applied in the same way as CSS transitions, the difference being that `v-enter` is not removed immediately after the element is inserted, but on an `animationend` event. +CSS 动画用法同 CSS 过渡,区别是在动画中 `v-enter` 类名在节点插入 DOM 后不会立即删除,而是在 `animationend` 事件触发时删除。 Here's an example, omitting prefixed CSS rules for the sake of brevity: +为了简洁,下面的示例省略了兼容浏览器的 CSS 前缀: ``` html
      @@ -314,9 +339,10 @@ new Vue({ {% endraw %} -### Custom Transition Classes +### 自定义过渡类名 (Custom Transition Classes) You can also specify custom transition classes by providing the following attributes: +你也可以通过提供以下属性来声明自定义过渡类名: - `enter-class` - `enter-active-class` @@ -324,8 +350,10 @@ You can also specify custom transition classes by providing the following attrib - `leave-active-class` These will override the conventional class names. This is especially useful when you want to combine Vue's transition system with an existing CSS animation library, such as [Animate.css](https://daneden.github.io/animate.css/). +这些会覆盖传统类名。当你想结合 Vue 的过渡系统和已有的 CSS 动画库如 [Animate.css](https://daneden.github.io/animate.css/) 时非常有用。 Here's an example: +例如: ``` html @@ -377,15 +405,18 @@ new Vue({ {% endraw %} -### Using Transitions and Animations Together +### 过渡与动画一起使用 (Using Transitions and Animations Together) Vue needs to attach event listeners in order to know when a transition has ended. It can either be `transitionend` or `animationend`, depending on the type of CSS rules applied. If you are only using one or the other, Vue can automatically detect the correct type. +Vue 需要通过添加事件监听器来获知一次过渡是否结束。这个事件可以是 `transitionend` 或 `animationend`,取决于应用的 CSS 类型。如果你一次只使用两者中的一种,Vue 将会自动检测对应的事件类型。 However, in some cases you may want to have both on the same element, for example having a CSS animation triggered by Vue, along with a CSS transition effect on hover. In these cases, you will have to explicitly declare the type you want Vue to care about in a `type` attribute, with a value of either `animation` or `transition`. +然而,在某些情况下同一个目标元素可能同时应用过渡和动画,例如某个元素能被 Vue 触发动画效果,同时在鼠标悬浮时也有一个 CSS 过渡效果。这种情况下,你需要在 `type` 属性中明确地声明你想让 Vue 处理的过渡类型, `type` 属性的值可以是 `animation` 或 `transition`。 -### JavaScript Hooks +### JavaScript 钩子 (JavaScript Hooks) You can also define JavaScript hooks in attributes: +你也能在属性中定义 JavaScript 钩子函数: ``` html When using JavaScript-only transitions, **the `done` callbacks are required for the `enter` and `leave` hooks**. Otherwise, they will be called synchronously and the transition will finish immediately.

      +

      When using JavaScript-only transitions, **the `done` callbacks are required for the `enter` and `leave` hooks**. Otherwise, they will be called synchronously and the transition will finish immediately. +当使用纯 JavaScript 过渡时, **需要在 `enter` 和 `leave` 中提供 `done` 回调函数**。否则 `enter` 和 `leave` 就会被同步调用,过渡立即结束。

      -

      It's also a good idea to explicitly add `v-bind:css="false"` for JavaScript-only transitions so that Vue can skip the CSS detection. This also prevents CSS rules from accidentally interfering with the transition.

      +

      It's also a good idea to explicitly add `v-bind:css="false"` for JavaScript-only transitions so that Vue can skip the CSS detection. This also prevents CSS rules from accidentally interfering with the transition. +同时也推荐为纯 JavaScript 过渡添加 `v-bind:css="false"` 以跳过 CSS 检测,这也能有效防止过渡中 CSS 的意外干扰。

      Now let's dive into an example. Here's a simple JavaScript transition using Velocity.js: +让我们来看一个例子。这是应用了 Velocity.js 的简单 JavaScript 过渡效果 ``` html +
      @@ -555,9 +594,10 @@ new Vue({ {% endraw %} -## Transitions on Initial Render +## 初始渲染的过渡 (Transitions on Initial Render) If you also want to apply a transition on the initial render of a node, you can add the `appear` attribute: +如果想在节点的第一次渲染时应用过渡效果,你可以添加 `appear` 属性: ``` html @@ -566,6 +606,7 @@ If you also want to apply a transition on the initial render of a node, you can ``` By default, this will use the transitions specified for entering and leaving. If you'd like however, you can also specify custom CSS classes: +默认地,这会使用进入/离开的过渡。但如果你喜欢,也可以声明自定义 CSS 类名: ``` html ``` -## Transitioning Between Elements +## 元素之间的过渡 (Transitioning Between Elements) We discuss [transitioning between components](#Transitioning-Between-Components) later, but you can also transition between raw elements using `v-if`/`v-else`. One of the most common two-element transitions is between a list container and a message describing an empty list: +我们将会在稍后讨论 [组件之间的过渡](#Transitioning-Between-Components),你也可以使用 `v-if`/`v-else` 进行普通元素之间的过渡。最常见的两元素过渡之一是列表包裹容器和描述空列表的提示之间的过渡: ``` html @@ -604,10 +647,13 @@ We discuss [transitioning between components](#Transitioning-Between-Components) ``` This works well, but there's one caveat to be aware of: +这事例没问题,但需要注意: -

      When toggling between elements that have **the same tag name**, you must tell Vue that they are distinct elements by giving them unique `key` attributes. Otherwise, Vue's compiler will only replace the content of the element for efficiency. Even when technically unnecessary though, **it's considered good practice to always key multiple items within a `` component.**

      +

      When toggling between elements that have **the same tag name**, you must tell Vue that they are distinct elements by giving them unique `key` attributes. Otherwise, Vue's compiler will only replace the content of the element for efficiency. Even when technically unnecessary though, **it's considered good practice to always key multiple items within a `` component.** +当在两个标签名相同的元素之间过渡时,必须通过赋予它们唯一的 `key` 属性值以告诉 Vue 它们是不同的元素。否则,Vue 的编译器会为了高效率,单纯替换标签中的内容。即使在技术上看起来没那么必要,**在 `` 组件中总是为多个元素分别提供唯一的 `key` 值依然是最佳实践。**

      For example: +例如: ``` html @@ -621,6 +667,7 @@ For example: ``` In these cases, you can also use the `key` attribute to transition between different states of the same element. Instead of using `v-if` and `v-else`, the above example could be rewritten as: +在这些情况下,也能使用 `key` 属性使同一元素在不同状态下过渡。除了使用 `v-if` 和 `v-else` ,上面的例子也能重写为: ``` html @@ -631,6 +678,7 @@ In these cases, you can also use the `key` attribute to transition between diffe ``` It's actually possible to transition between any number of elements, either by using multiple `v-if`s or binding a single element to a dynamic property. For example: +在任意数量的元素中过渡也是可行的,可使用多个 `v-if`,或将单一元素绑定到一个动态属性中。例如: ``` html @@ -647,6 +695,7 @@ It's actually possible to transition between any number of elements, either by u ``` Which could also be written as: +可被写为: ``` html @@ -669,9 +718,10 @@ computed: { } ``` -### Transition Modes +### 过渡模式 (Transition Modes) There's still one problem though. Try clicking the button below: +还有一个问题。试试点击下面的按钮: {% raw %}
      @@ -703,8 +753,10 @@ new Vue({ {% endraw %} As it's transitioning between the "on" button and the "off" button, both buttons are rendered - one transitioning out while the other transitions in. This is the default behavior of `` - entering and leaving happens simultaneously. +因为是在 “on” 和 “off” 这两个按钮间过渡,两个按钮均被渲染————一个过渡离开而另一个过渡进入。这是 `` 的默认行为————元素或组件间的进入与离开同时发生。 Sometimes this works great, like when transitioning items are absolutely positioned on top of each other: +有时这很有用,像是两个绝对定位的叠加在对方上的元素过渡时: {% raw %}
      @@ -745,7 +797,7 @@ new Vue({ {% endraw %} And then maybe also translated so that they look like slide transitions: - +或是使元素位移形成滑动过渡的效果: {% raw %}
      @@ -791,16 +843,19 @@ new Vue({ {% endraw %} Simultaneous entering and leaving transitions aren't always desirable though, so Vue offers some alternative **transition modes**: +然而同时进入离开的过渡不总是令人满意。因此 Vue 提供了一些额外的 **过渡状态**: - `in-out`: New element transitions in first, then when complete, the current element transitions out. - +`in-out`:新元素先过渡进入,当过渡完成后,当前元素过渡离开。 - `out-in`: Current element transitions out first, then when complete, the new element transitions in. +`out-in`:当前元素先过渡离开,当过渡完成后,新元素过渡进入。 Now let's update the transition for our on/off buttons with `out-in`: - +现在使用 `out-in` 重写开/关按钮的过渡效果: ``` html + ``` @@ -834,8 +889,10 @@ new Vue({ {% endraw %} With one simple attribute addition, we've fixed that original transition without having to add any special styling. +这一简单的添加属性解决了原本过渡只能同时进入与离开的问题,并且没有额外添加任何特殊样式。 The `in-out` mode isn't used as often, but can sometimes be useful for a slightly different transition effect. Let's try combining it with the slide-fade transition we worked on earlier: + `in-out` 模式没有 `out-in` 的使用频率高,但有时也能在一些稍微不同的过渡效果中非常有用。尝试结合前面的滑动-褪色过渡效果: {% raw %}
      @@ -882,10 +939,12 @@ new Vue({ {% endraw %} Pretty cool, right? +很帅吧? -## Transitioning Between Components +## 组件间的过渡 (Transitioning Between Components) Transitioning between components is even simpler - we don't even need the `key` attribute. Instead, we just wrap a [dynamic component](components.html#Dynamic-Components): +组件间的过渡更加简单————甚至不需要 `key` 属性。我们只需包裹一个[动态组件](components.html#Dynamic-Components): ``` html @@ -953,21 +1012,28 @@ new Vue({ {% endraw %} -## List Transitions +## 列表过渡 (List Transitions) So far, we've managed transitions for: +至今为止,我们已经了解了以下过渡: - Individual nodes +独立节点 - Multiple nodes where only 1 is rendered at a time +多节点,每次只渲染一个节点 So what about for when we have a whole list of items we want to render simultaneously, for example with `v-for`? In this case, we'll use the `` component. Before we dive into an example though, there are a few things that are important to know about this component: +那么当试图同时渲染一个列表,例如说使用 `v-for` ,该怎么办呢?在这种情况下,我们使用 `` 组件。在看例子前,使用该组件有几个注意事项: - Unlike ``, it renders an actual element: a `` by default. You can change the element that's rendered with the `tag` attribute. +与 `` 不同,它渲染出一个真实的元素:默认为 ``。可以通过修改 `tag` 属性改变渲染出的元素类型。 - Elements inside are **always required** to have a unique `key` attribute +被包裹在里面的元素**总是需要**一个唯一的 `key` 属性值。 -### List Entering/Leaving Transitions +### 列表进入/离开过渡 (List Entering/Leaving Transitions) Now let's dive into a simple example, transitioning entering and leaving using the same CSS classes we've used previously: +现在来看一个简单的例子,使用前面的过渡进入/离开 CSS 类名: ``` html
      @@ -1062,12 +1128,15 @@ new Vue({ {% endraw %} There's one problem with this example. When you add or remove an item, the ones around it instantly snap into their new place instead of smoothly transitioning. We'll fix that later. +这个示例有一个问题:当你添加或移除列表项,其它的列表项会马上出现在新的位置而不是平滑过渡。我们稍后回来修复这个问题。 -### List Move Transitions +### 列表移动过渡 (List Move Transitions) -The `` component has another trick up its sleeve. It can not only animate entering and leaving, but also changes in position. The only new concept you need to know to use this feature is the addition of **the `v-move` class**, which is added when items are changing positions. Like the other classes, its prefix will match the value of match a provided `name` attribute and you can also manually specify a class with the `move-class` attribute. +The `` component has another trick up its sleeve. It can not only animate entering and leaving, but also changes in position. The only new concept you need to know to use this feature is the addition of **the `v-move` class**, which is added when items are changing positions. Like the other classes, its prefix will match the value of a provided `name` attribute and you can also manually specify a class with the `move-class` attribute. +另一个 `` 组件的使用技巧是:它不仅能将进入和离开动效化,还可以让位置改变获得动效。为了使用这个特性,你唯一需要知道的新概念是** `v-move` 类**的添加。当列表项的位置发生改变,`v-move` 类便会被添加。像其它类一样,它的前缀也与组件提供的 `name` 属性值相同,你也可以使用 `move-class` 属性手动声明这个类。 This class is mostly useful for specifying the transition timing and easing curve, as you'll see below: +正如下面所示,这个类会在定义过渡时间和缓冲曲线时发挥最大作用: ``` html @@ -1084,7 +1153,7 @@ This class is mostly useful for specifying the transition timing and easing curv ``` js new Vue({ - el: '#list-move-demo', + el: '#flip-list-demo', data: { items: [1,2,3,4,5,6,7,8,9] }, @@ -1133,8 +1202,10 @@ new Vue({ {% endraw %} This might seem like magic, but under the hood, Vue is using a simple animation technique called [FLIP](https://aerotwist.com/blog/flip-your-animations/) to smoothly transition elements from their old position to their new position using transforms. +这可能看起来很神奇,但实际上 Vue 使用了一个简单的动画技术 [FLIP](https://aerotwist.com/blog/flip-your-animations/),使元素能够从旧位置平滑过渡到新位置。 We can combine this technique with our previous implementation to animate every possible change to our list! +现在我们可以结合前面的实现,让列表的任意改变都能拥有动画效果: ``` html @@ -1245,9 +1316,11 @@ new Vue({ {% endraw %} -

      One important note is that these FLIP transitions do not work with elements set to `display: inline`. As an alternative, you can use `display: inline-block` or place elements in a flex context.

      +

      One important note is that these FLIP transitions do not work with elements set to `display: inline`. As an alternative, you can use `display: inline-block` or place elements in a flex context. +特别要注意,FLIP 过渡无法应用在 `display: inline` 的元素上。备选的方案是,使用 `display: inline-block` 或把元素放在一个 flex 布局中。

      These FLIP animations are also not limited to a single axis. Items in a multidimensional grid can transitioned [just as easily](https://jsfiddle.net/chrisvfritz/sLrhk1bc/): +这些 FLIP 动画不局限于单个轴。在多维的网格中的列表也能[同样轻松](https://jsfiddle.net/chrisvfritz/sLrhk1bc/)地过渡: {% raw %}
      @@ -1310,9 +1383,10 @@ new Vue({ {% endraw %} -### Staggering List Transitions +### 错开列表过渡 (Staggering List Transitions) By communicating with JavaScript transitions through data attributes, it's also possible to stagger transitions in a list: +通过在 JavaScript 过渡中使用数据属性,你还能在列表中实现错开过渡: ``` html @@ -1456,11 +1530,10 @@ new Vue({ {% endraw %} -## Reusable Transitions +## 可重用过渡 (Reusable Transitions) Transitions can be reused through Vue's component system. To create a reusable transition, all you have to do is place a `` or `` component at the root, then pass any children into the transition component. - -Here's an example using a template component: +通过 Vue 的组件系统,过渡也可以被重用。要创建一个可重用过渡,只需将 `` 或 `` 组件置于根节点,并向过渡组件中传入任意子节点。 ``` js Vue.component('my-special-transition', { @@ -1468,7 +1541,7 @@ Vue.component('my-special-transition', { \ \ @@ -1486,6 +1559,7 @@ Vue.component('my-special-transition', { ``` And functional components are especially well-suited to this task: +函数式组件尤其适合这种情况: ``` js Vue.component('my-special-transition', { @@ -1510,9 +1584,10 @@ Vue.component('my-special-transition', { }) ``` -## Dynamic Transitions +## 动态过渡 (Dynamic Transitions) Yes, even transitions in Vue are data-driven! The most basic example of a dynamic transition binds the `name` attribute to a dynamic property. +Vue 中的动态过渡也是数据驱动的。动态过渡最简单的一个例子,就是将 `name` 属性被绑定到一个动态属性: ```html @@ -1521,8 +1596,10 @@ Yes, even transitions in Vue are data-driven! The most basic example of a dynami ``` This can be useful when you've defined CSS transitions/animations using Vue's transition class conventions and simply want to switch between them. +当你使用 Vue 的过渡类名约定定义多个 CSS 过渡/动画类名并想在它们之间转换时,动态绑定显得非常有用。 Really though, any transition attribute can be dynamically bound. And it's not just attributes. Since event hooks are just methods, they have access to any data in the context. That means depending on the state of your component, your JavaScript transitions can behave differently. +实际上,任意过渡属性都能被动态绑定。而且不仅仅是属性,因为钩子只是函数,所以钩子也能从上下文获取数据。这意味着你的 JavaScript 过渡能根据组件的状态而拥有不同的行为。 ``` html @@ -1653,4 +1730,4 @@ new Vue({ {% endraw %} Finally, the ultimate way of creating dynamic transitions is through components that accept props to change the nature of the transition(s) to be used. It may sound cheesy, but the only limit really is your imagination. - +最后,创建动态过渡的终极方法是,就是通过接收属性的组件来改变过渡。虽然听来有点俗,不过唯一限制着你的,只有你的想象力。 diff --git a/src/guide/unit-testing.md b/src/guide/unit-testing.md index adaf69ec4a..064add099c 100644 --- a/src/guide/unit-testing.md +++ b/src/guide/unit-testing.md @@ -1,16 +1,18 @@ --- -title: Unit Testing +title: 单元测试 (Unit Testing) type: guide -order: 22 +order: 23 --- -## Setup and Tooling +## 安装与工具 (Setup and Tooling) -Anything compatible with a module-based build system will work, but if you're looking for a specific recommendation, try the [Karma](http://karma-runner.github.io/0.12/index.html) test runner. It has a lot of community plugins, including support for [Webpack](https://github.com/webpack/karma-webpack) and [Browserify](https://github.com/Nikku/karma-browserify). For detailed setup, please refer to each project's respective documentation, though these example Karma configurations for [Webpack](https://github.com/vuejs/vue-loader-example/blob/master/build/karma.conf.js) and [Browserify](https://github.com/vuejs/vueify-example/blob/master/karma.conf.js) may help you get started. +Anything compatible with a module-based build system will work, but if you're looking for a specific recommendation, try the [Karma](http://karma-runner.github.io) test runner. It has a lot of community plugins, including support for [Webpack](https://github.com/webpack/karma-webpack) and [Browserify](https://github.com/Nikku/karma-browserify). For detailed setup, please refer to each project's respective documentation, though these example Karma configurations for [Webpack](https://github.com/vuejs-templates/webpack/blob/master/template/test/unit/karma.conf.js) and [Browserify](https://github.com/vuejs-templates/browserify/blob/master/template/karma.conf.js) may help you get started. +你可以使用任何兼容模块化构建的测试工具。如果你需要个具体建议,可以试试 [Karma](http://karma-runner.github.io/0.12/index.html)。它有很多的社区插件,包括对 [Webpack](https://github.com/webpack/karma-webpack) 和 [Browserify](https://github.com/Nikku/karma-browserify) 的支持。至于具体的安装细节,请参考各个项目的文档。这里有两个karma的配置实例,能够帮助你快速入门。一个是对 [Webpack](https://github.com/vuejs-templates/webpack/blob/master/template/test/unit/karma.conf.js),另一个是对 [Browserify](https://github.com/vuejs-templates/browserify/blob/master/template/karma.conf.js)。 -## Simple Assertions +## 简单断言 (Simple Assertions) In terms of code structure for testing, you don't have to do anything special in your components to make them testable. Just export the raw options: +就测试的代码结构而言,你不需要在组件里做任何特别的事,就能进行测试。只要导入以下选项: ``` html