目录
一、单文件组件
1、介绍
2、怎么看待关注点分离?
(1)例子沙盒
(2)针对刚开始接触JavaScript模块系统开发的用户
(3)针对高级用户
二、单元测试
1、简单的断言
2、编写可被测试的组件
3、断言异步更新
一、单文件组件
1、介绍
在很多 Vue 项目中,我们使用 Vue.component
来定义全局组件,紧接着用 new Vue({ el: '#container '})
在每个页面内指定一个容器元素。
这种方式在很多中小规模的项目中运作的很好,在这些项目里 JavaScript 只被用来加强特定的视图。但当在更复杂的项目中,或者你的前端完全由 JavaScript 驱动的时候,下面这些缺点将变得非常明显:
- 全局定义 (Global definitions) 强制要求每个 component 中的命名不得重复
- 字符串模板 (String templates) 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的
\
- 不支持 CSS (No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
- 没有构建步骤 (No build step) 限制只能使用 HTML 和 ES5 JavaScript, 而不能使用预处理器,如 Pug (formerly Jade) 和 Babel
文件扩展名为 .vue
的 single-file components(单文件组件) 为以上所有问题提供了解决方法,并且还可以使用 webpack 或 Browserify 等构建工具。
这是一个文件名为 Hello.vue
的简单实例:
scoped: 如果使用该属性,则样式仅仅应用到 style 元素的父元素及其子元素。
exports:首先对于本身来讲是一个变量(对象),它不是module的引用,它是{}的引用,它指向module.exports的{}模块
module.exports:首先,module是一个变量,指向一块内存,exports是module中的一个属性,存储在内存中,然后exports属性指向{}模块
exports只能使用.语法向外暴露内部变量 例 exports.xxx=xxx
module.exports既可以通过点语法,也可以直接赋值一个对象 例 module.exports.xxx=xxx
module.exports=xxx
现在我们获得:
- 完整语法高亮
- CommonJS 模块
- 组件作用域的 CSS
正如我们说过的,我们可以使用预处理器来构建简洁和功能更丰富的组件,比如 Pug,Babel (with ES2015 modules),和 Stylus。
这些特定的语言只是例子,你可以只是简单地使用 Babel,TypeScript,SCSS,PostCSS - 或者其他任何能够帮助你提高生产力的预处理器。如果搭配 vue-loader
使用 webpack,它也能为 CSS Modules 提供头等支持。
2、怎么看待关注点分离?
一个重要的事情值得注意,关注点分离不等于文件类型分离。在现代 UI 开发中,我们已经发现相比于把代码库分离成三个大的层次并将其相互交织起来,把它们划分为松散耦合的组件再将其组合起来更合理一些。在一个组件里,其模板、逻辑和样式是内部耦合的,并且把他们搭配在一起实际上使得组件更加内聚且更可维护。
即便你不喜欢单文件组件,你仍然可以把 JavaScript、CSS 分离成独立的文件然后做到热重载和预编译。
<!-- my-component.vue -->
<template>
<div>This will be pre-compiled</div>
</template>
<script src="./my-component.js"></script>
<style src="./my-component.css"></style>
(1)例子沙盒
如果你希望深入了解并开始使用单文件组件,请来 CodeSandbox 看看这个简单的 todo 应用。
(2)针对刚开始接触JavaScript模块系统开发的用户
有了 .vue
组件,我们就进入了高级 JavaScript 应用领域。如果你没有准备好的话,意味着还需要学会使用一些附加的工具:
-
Node Package Manager (NPM):阅读 Getting Started guide 直到 10: Uninstalling global packages章节。
-
Modern JavaScript with ES2015/16:阅读 Babel 的 Learn ES2015 guide。你不需要立刻记住每一个方法,但是你可以保留这个页面以便后期参考。
在你花一天时间了解这些资源之后,我们建议你参考 Vue CLI 3。只要遵循指示,你就能很快地运行一个带有 .vue
组件、ES2015、webpack 和热重载 (hot-reloading) 的 Vue 项目!
(3)针对高级用户
CLI 会为你搞定大多数工具的配置问题,同时也支持细粒度自定义配置项。
有时你会想从零搭建你自己的构建工具,这时你需要通过 Vue Loader 手动配置 webpack。关于学习更多 webpack 的内容,请查阅其官方文档 和 Webpack Academy。
二、单元测试
Vue CLI 拥有开箱即用的通过 Jest 或 Mocha 进行单元测试的内置选项。我们还有官方的 Vue Test Utils 提供更多详细的指引和自定义设置。
1、简单的断言
你不必为了可测性在组件中做任何特殊的操作,导出原始设置就可以了:
<template>
<span>{{ message }}</span>
</template>
<script>
export default {
data () {
return {
message: 'hello!'
}
},
created () {
this.message = 'bye!'
}
}
</script>
然后随着 Vue 导入组件的选项,你可以使用许多常见的断言 (这里我们使用的是 Jasmine/Jest 风格的 expect
断言作为示例):
// 导入 Vue.js 和组件,进行测试
import Vue from 'vue'
import MyComponent from 'path/to/MyComponent.vue'
// 这里是一些 Jasmine 2.0 的测试,你也可以使用你喜欢的任何断言库或测试工具。
describe('MyComponent', () => {
// 检查原始组件选项
it('has a created hook', () => {
expect(typeof MyComponent.created).toBe('function')
})
// 评估原始组件选项中的函数的结果
it('sets the correct default data', () => {
expect(typeof MyComponent.data).toBe('function')
const defaultData = MyComponent.data()
expect(defaultData.message).toBe('hello!')
})
// 检查 mount 中的组件实例
it('correctly sets the message when created', () => {
const vm = new Vue(MyComponent).$mount()
expect(vm.message).toBe('bye!')
})
// 创建一个实例并检查渲染输出
it('renders the correct message', () => {
const Constructor = Vue.extend(MyComponent)
const vm = new Constructor().$mount()
expect(vm.$el.textContent).toBe('bye!')
})
})
2、编写可被测试的组件
很多组件的渲染输出由它的 props 决定。事实上,如果一个组件的渲染输出完全取决于它的 props,那么它会让测试变得简单,就好像断言不同参数的纯函数的返回值。看下面这个例子:
<template>
<p>{{ msg }}</p>
</template>
<script>
export default {
props: ['msg']
}
</script>
你可以在不同的 props 中,通过 propsData
选项断言它的渲染输出:
import Vue from 'vue'
import MyComponent from './MyComponent.vue'
// 挂载元素并返回已渲染的文本的工具函数
function getRenderedText (Component, propsData) {
const Constructor = Vue.extend(Component)
const vm = new Constructor({ propsData: propsData }).$mount()
return vm.$el.textContent
}
describe('MyComponent', () => {
it('renders correctly with different props', () => {
expect(getRenderedText(MyComponent, {
msg: 'Hello'
})).toBe('Hello')
expect(getRenderedText(MyComponent, {
msg: 'Bye'
})).toBe('Bye')
})
})
3、断言异步更新
由于 Vue 进行 异步更新 DOM 的情况,一些依赖 DOM 更新结果的断言必须在 Vue.nextTick
回调中进行:
// 在状态更新后检查生成的 HTML
it('updates the rendered message when vm.message updates', done => {
const vm = new Vue(MyComponent).$mount()
vm.message = 'foo'
// 在状态改变后和断言 DOM 更新前等待一刻
Vue.nextTick(() => {
expect(vm.$el.textContent).toBe('foo')
done()
})
})
关于更深入的 Vue 单元测试的内容,请移步 Vue Test Utils 以及我们关于 Vue 组件的单元测试的 cookbook 文章。