可复用的组件
在编写组件时,对于可复用的组件,要定义清晰接口(API),同时也不要对外部使用的数据做出任何假设方便复用。
Vue 组件的 API 来自三部分——prop、事件和插槽:
- props 外部环境传递给组件的数据
- 事件 从组件内部触发的外部环境的副作用
插槽 外部环境将额外的内容组合在组件中
上面时官网的定义,也就是说当我们考虑组件的复用时要自觉地考虑这三部分,同时在看别人写好的组件时也要自觉看别人如何定义的。
// todo 这里事件部分需要再加强理解
<my-component
:foo="baz"
:bar="qux"
@event-a="doThis"
@event-b="doThat"
>
<img slot="icon" src="...">
<p slot="main-text">Hello!</p>
</my-component>
子组件引用
尽管有 prop 和事件,但是有时仍然需要在 JavaScript 中直接访问子组件。为此可以使用 ref 为子组件指定一个引用 ID。例如:
首先是在js中直接访问子组件,相当于给子组件指定ref属性值,在父组件的$refs
中有存有各子组件的引用。这里先不管具体应用场景,先记住。
<!-- 当 ref 和 v-for 一起使用时,获取到的引用会是一个数组,包含和循环数据源对应的子组件。 -->
<div id="parent">
<user-profile ref="profile"></user-profile>
</div>
var parent = new Vue({ el: '#parent' })
// 访问子组件实例
var child = parent.$refs.profile
$refs
只在组件渲染完成后才填充,并且它是非响应式的。它仅仅是一个直接操作子组件的应急方案——应当避免在模板或计算属性中使用 $refs。
异步组件
将组件分成小块,需要时从服务器异步加载。
为了进一步简化,Vue.js 允许将组件定义为一个工厂函数,异步地解析组件的定义。Vue.js 只在组件需要渲染时触发工厂函数,并且把结果缓存起来,用于后面的再次渲染。
原来组件使用步骤是:
//user.js
export default {
template: '<div>A custom component!</div>'
}
// 引入,并注册
const User = import('user')
{
components: User //原来组件是个对象,或者是个渲染函数
}
在异步组件中,组件是一个工厂函数,异步解析组件的定义。这里既然是个函数,免不了要调用。而这里是需要使用的时候再调用。
Vue.js 只在组件需要渲染时触发工厂函数,并且把结果缓存起来,用于后面的再次渲染。
为什么叫工厂函数,理解为产生组件的生产工厂。因此结构什么的应该是统一的,不看工厂函数的实现,这个函数返回的应该是我们实际的组件。相当于是这样方式
// 一般的异步加载某件东西的操作
{
components: function(){
// 异步获取并返回
ajax.getComponents('user',function(data){
return data.User
})
}
}
// 因此我觉得Vue组件内部判断是一个函数的,应该也是上面那种操作,作者帮我们做了一层封装, 并没有看源码,自己猜的,便于理解,然而目的就是一个异步加载数据。
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 将组件定义传入 resolve 回调函数
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
这里使用 setTimeout 只是为了演示,实际上如何获取组件完全由你决定。同时关于resolve的作用应该就是将异步获取的组件给返回出去。类似return的作用
异步加载已经实现,因为是个函数所以也会自动调用,现在问题是设置webpack的代码分割,把我们需要异步加载的组件给分出去,不用我们自己再操心如何加载,如何划分的事。
推荐配合 webpack 的代码分割功能 来使用:
Vue.component('async-webpack-example', function (resolve) {
// 这个特殊的 require 语法告诉 webpack
// 自动将编译后的代码分割成不同的块,
// 这些块将通过 Ajax 请求自动下载。
require(['./my-async-component'], resolve)
})
你可以在工厂函数中返回一个 Promise,所以当使用 webpack 2 + ES2015 的语法时可以这样:
// promise方式,使用promise目的之一就是统一异步流程
{
components: function(){
return new Promise((resolve,reject){
ajax.getComponents('user',function(data){
if('成功') resolve(data.User)
else reject(data.error)
})
})
}
}
这里import
函数的实现应该就是我上面promise实现方式的写法,而之前的方式应该resolve表示的应该是return的意思,
Vue.component(
'async-webpack-example',
// 该 `import` 函数返回一个 `Promise` 对象。
() => import('./my-async-component')
)
高级异步组件
// 自 2.3.0 起,异步组件的工厂函数也可以返回一个如下的对象:
const AsyncComp = () => ({
// 需要加载的组件。应当是一个 Promise
component: import('./MyComp.vue'),
// 加载中应当渲染的组件
loading: LoadingComp,
// 出错时渲染的组件
error: ErrorComp,
// 渲染加载中组件前的等待时间。默认:200ms。
delay: 200,
// 最长等待时间。超出此时间则渲染错误组件。默认:Infinity
timeout: 3000
})
注意,当一个异步组件被作为 vue-router 的路由组件使用时,这些高级选项都是无效的,因为在路由切换前就会提前加载所需要的异步组件。另外,如果你要在路由组件中使用上述写法,需要使用 vue-router 2.4.0 以上的版本。
上面加粗的还不是太理解,随着使用再来填坑。