在初学 Vue
的时候,都是利用 cdn
的方式在一个页面中导入 vue.js
的库文件.
<script src='https://cdn.jsdelivr.net/npm/vue/dist/vue.js'></script>
var app = new Vue({
el: '#app',
data: {
title: '我的第一个vue组件'
},
methods: {},
filters: {},
directives: {},
components: {},
})
接着,肯定就学到了组件开发.
当然,也是在单页面中.
API文档告诉我们
-
Vue.component
用来注册全局组件. - 在某个组件内部使用
components:{}
来注册局部组件.
<global-vue-component></global-vue-component>
Vue.component('GlobalVueComponent',{
template:`<div>{{title}}</div>`,
data () {
return {
title: '我是使用 Vue.component 注册的全局组件'
}
}
})
<scope-vue-component></scope-vue-component>
let ScopeVueComponent = {
template:`<div>{{title}}</div>`,
data () {
return {
title: '我是使用 components 使用的局部组件'
}
}
}
var app = new Vue({
el: '#app',
data: {
title: '我的第一个vue组件'
},
components: {
ScopeVueComponent
}
})
image.png
在后来,学到了使用 vue-cli
搭配 .vue
模板的方式开发组件.
<template>
<div>
{{ title }}
</div>
</template>
<script>
// 这是组件的数据和行为内容 vm & model
export default {
name:'vue-template-mode-component',
data () {
return {
title: '这是.vue组件的模板开发模式'
}
}
}
</script>
好了,三种组件创建的方式说完了,且在各自的环境里都能够正常的运作.
Vue.extend 方法.
在 Vue
开发中,所有的组件本质上都是由一个继承自 Vue
的构造函数创建的.
比如在注册局部组件时.
const TodoListComp = {
template:`<div><h1>{{ title }}</h1></div>`,
data () {
return {
title:'用 object 搭配 components 的方式去创建局部组件'
}
}
}
const app = new Vue({
el:'#app',
components: {
TodoListComp,
}
})
<todo-list-comp></todo-list-comp>
从视觉上,我们看到 TodoListComp
只是一个普通的 Object
对象.
直接赋值给了其他组件的components
属性里.
然后,这个组件就成为了一个局部组件,并可以在注册了当前组件的内部去使用了.
那它在内部做了什么,导致这个普通的对象最后可以被当成是一个正常的组件来使用呢?
比如,普通对象上都没有$el
之类的属性.丢给components
之后,就啥都有了.
其实,在
Vue
内部,所有的组件都是通过Vue.extend()
函数来构建的.
这个函数接收一个满足组件定义的object对象(比如,data,watch,computed,methods等).
最终返回一个构建此组件的构造函数(VueComponent)
使用Vue.extend(options)会根据传入的options创建一个VueComponent的组件构造函数并返回.
const TodoList = Vue.extend({
template:`<div><h1>{{ title }}</h1></div>`,
data () {
return {
title:'Vue.extend 创建的组件构造函数,使用new的方式创建并挂载'
}
}
})
console.log(TodoList)
image.png
既然使用 Vue.extend
会返回一个组件的构造函数.
那么我们就可以使用 new
这个返回的构造函数
并手动的 mount
并替换某个 dom
节点(就和 new App()
一样)
<!--用TodoListComp构造出来的组件实例对象替换这个节点-->
<div id="todolistcomp"></div>
const comp = new TodoList() // 这不不用传options,是因为在 Vue.extend(options) 的时候已经传递了.
comp.$mount('#todolistcomp') // 既然是创建出来的组件,继承自 Vue.prototype 所以就会有$mount 函数.
image.png
.vue 模板文件开发.
前面,我么已经知道了,所有的vue
组件,不管是全局的还是局部的.
都是利用 Vue.extend
方法构建并返回出一个继承自 Vue
的组件构造函数.
这个函数接受一个满足了 Vue
组件属性项的普通的 Object
对象.
在.vue模板文件开发中,也不例外.
我们可以看看,在书写.vue
模板文件时,我们到底在写什么?
<template>
<div>
<h2>{{title}}</h2>
<p v-html="content"></p>
</div>
</template>
<script>
export default {
name:'about-vue-template',
data() {
return {
title:"我是.vue模板创建的组件",
content:"使用.vue模板文件创建的组件本质上是vue-loader将这个文件编译成一个普通的不能在普通的obj对象.[template]xxxxx[/template]就被定义成对象的<b color='red'>.template属性.</b> 其他属性同理<ul><li>data</li><li>watch</li><li>methods</li><li>computed</li></ul>"
}
},
directives:{},
computed: {},
methods: {},
filters: {}
}
我们写的是一个 .vue 文件.
并按照 <template></template> <script></script>
(这里不关注<style></style>
节点) 的格式编写 .vue
文件.
把它整合起来来看.
-
template
就有点像我们在定普通组件options对象时的template
属性. -
data
就是options
对象的data
-
methods
就是options
对象的methods
-
computed
就是options
对象的computed
-
filters
就是options
对象的filters
等价于
const normalObjectOptions = {
template:
data:
methods:
computed:
filters:
}
好了,继续回到 .vue
模板开发文件中.
在另外一个组件中,使用此组件时,我们会 import xxx from xxx.vue
并搭配 components:{ xxxx }
.vue
会被 webpack
中配置的 vue-loader
处理.这是我们已知的.
结合上述的判断,vue-loader
仅仅只是把 .vue
文件编译成了一个 vue.extend(options)
创建组件所需要的 options
普通对象而已.
// 导入一个.vue文件的模板
import AboutVueComp from './components/about'
// 查看实际导出的数据
console.log('AboutVueComp',AboutVueComp)
image.png
既然 vue-loader
仅仅,只是把 .vue
模板文件编译成了一个 options
普通对象.
那么我们可以手动的使用 Vue.extends(options)
来获得这个组件对象的构造函数.
const AboutVueCompConstructor = Vue.extend(AboutVueComp)
console.log('AboutVueCompConstructor',AboutVueCompConstructor)
image.png
拿到此组件的构造函数,我们就可以在 组件 mounted
的时候,通过 new
的方式,挂在到 html
上了. (而无需去注册到 components,成为一个局部组件.直接把它当成一个自己熟悉的不能在熟悉的构造函数调用即可.)
// 导入一个.vue文件的模板
import AboutVueComp from './components/about'
// 查看实际导出的数据
console.log('AboutVueComp',AboutVueComp) // object
const AboutVueCompConstructor = Vue.extend(AboutVueComp)
console.log('AboutVueCompConstructor',AboutVueCompConstructor)
mounted() {
new AboutVueCompConstructor().$mount('#aboutvuecompcontstrutor')
},
image.png
使用.js文件的方式使用.vue组件.
既然我们已经知道:
-
.vue
模板文件本质上会被vue-loader
编译成了一个普通的不能在普通的object
对象. - 这个对象里包含了
vue
组件需要的一些数据和方法. - 然后接着使用
Vue.extend()
接受这个普通的不能在普通的object
对象. - 并返回一个创建此对象的构造函数
f VueComponent(options){ this._init(options) }
. - 最后,我们就可以使用 new 构造函数的方式来创建此组件.
我们完全可以直接使用 .js
文件的方式来创建 vue
组件,进而省略 .vue
& vue-loader
这个执行的步骤.
import Vue from 'vue'
export default Vue.extend({
name: 'js-comp-constructor',
template: `<div @click="hanlderClick">{{title}}</div>`,
data () {
return {
title: "我是通过.js文件创建出来的组件"
}
},
methods: {
hanlderClick () {
console.log('我是js模式组件提供的click方法')
}
},
mounted () {
this.$el.style.width = '300px'
this.$el.style.height = '200px'
this.$el.style.backgroundColor = 'red'
this.$el.style.margin ='0 auto'
this.$el.style.lineHeight = '200px'
this.$el.style.color = '#fff'
this.$el.style.textAlign = 'center'
}
})
此.js
文件到处一个vue
组件的构造函数.
在另外一个组件里
import JsCompConstructor from './components/js-comp-constructor'
注册这个组件:
components: {
JsCompConstructor
}
使用这个组件
<JsCompConstructor></JsCompConstructor>
image.png
通过这样的原理,我们完全可以在HTML页面的任意地方,任意位置,任意的挂在我们自己的组件.并不一定必须使用.vue声明式组件的语法.
最后总结
- 在 vue 开发中,组件是很常见的.
- 组件分局部组件和全局组件
- 组件的本质是通过 Vue.extend(options)来构建出一个组件的构造函数.
- 组件对象 options 写法有两种.
- .vue 模板格式.
- 搭配 vue-loader 就编译成一个普通的 options 对象.
- .js 格式.
- 提供一个满足组件options的对象.
- 通过 Vue.extend() 拿到组件构造函数
- 我们就可以很自由的在任意时间,任意地方去挂载我们的组件了.
- .vue 模板格式.
[码云地址]
网友评论