什么是组件
1.非单文件组件
基本使用
<div id="root">
<hello></hello>
<hr />
<h1>{{msg}}</h1>
<hr />
<!-- 第三步:编写组件标签 -->
<blog></blog>
<hr />
<!-- 第三步:编写组件标签 -->
<student></student>
</div>
<div id="root2">
<hello></hello>
</div>
<script type="text/javascript">
// 第一步:创建 blog 组件
const blog = Vue.extend({
// 组件定义时,一定不要写 el 配置项,因为最终所有的组件都要被一个 vm 管理,由 vm 决定服务于哪个容器。
// el:'#root',
template: `
<div class="demo">
<h2>博客名称:{{blogName}}</h2>
<h2>博客地址:{{address}}</h2>
<button @click="showName">点我提示博客名</button>
</div>
`,
data() {
// 组件方式要写函数式,对象具有引用关系,函数则返回一个新对象,不存在引用关系
return {
blogName: "星宿君 の Blog",
address: "https://blog.huxinfeng.com",
};
},
methods: {
showName() {
alert(this.blogName);
},
},
});
// 第一步:创建 student 组件
const student = Vue.extend({
template: `
<div>
<h2>同学姓名:{{studentName}}</h2>
<h2>同学年龄:{{age}}</h2>
</div>
`,
data() {
return {
studentName: "张三",
age: 18,
};
},
});
// 第一步:创建 hello 组件
const hello = Vue.extend({
template: `
<div>
<h2>你好啊!{{name}}</h2>
</div>
`,
data() {
return {
name: "Tom",
};
},
});
// 第二步:全局注册组件
Vue.component("hello", hello);
// 创建 vm
new Vue({
el: "#root",
data: {
msg: "你好啊!",
},
// 第二步:注册组件(局部注册)
components: {
blog,
student,
},
});
new Vue({
el: "#root2",
});
</script>
小结
- Vue 中使用组件的三大步骤:
(1) 定义组件(创建组件)
(2) 注册组件
(3) 使用组件(写组件标签) - 如何定义一个组件?
使用 Vue.extend(options)创建,其中 options 和 new Vue(options)时传入的那个 options 几乎一样,但也有点区别;
区别如下:
(1) el 不要写,为什么?
——— 最终所有的组件都要经过一个 vm 的管理,由 vm 中的 el 决定服务哪个容器。
(2) data 必须写成函数,为什么?
——— 避免组件被复用时,数据存在引用关系。
备注:使用 template 可以配置组件结构。 - 如何注册组件?
(1) 局部注册:靠 new Vue 的时候传入 components 选项
(2) 全局注册:靠 Vue.component('组件名',组件) - 编写组件标签:
几个注意点
<div id="root">
<h1>{{msg}}</h1>
<blog></blog>
</div>
<script type="text/javascript">
// 定义组件
const s = Vue.extend({
// 开发者工具栏显示的组件名
name: "huxinfeng",
template: `
<div>
<h2>博客名称:{{name}}</h2>
<h2>博客地址:{{address}}</h2>
</div>
`,
data() {
return {
name: "星宿君 の Blog",
address: "https://blog.huxinfeng.com",
};
},
});
new Vue({
el: "#root",
data: {
msg: "欢迎学习Vue!",
},
components: {
blog: s,
},
});
</script>
小结
几个注意点:
- 关于组件名:
一个单词组成:
第一种写法(首字母小写):blog
第二种写法(首字母大写):Blog
多个单词组成:
第一种写法(kebab-case 命名):my-blog
第二种写法(CamelCase 命名):MyBlog (需要 Vue 脚手架支持)
备注:
(1) 组件名尽可能回避 HTML 中已有的元素名称,例如:h2、H2 都不行。
(2) 可以使用 name 配置项指定组件在开发者工具中呈现的名字。 - 关于组件标签:
第一种写法:
第二种写法:
备注:不用使用脚手架时,会导致后续组件不能渲染,即多个 只会渲染一个。 - 一个简写方式:
const blog = Vue.extend(options) 可简写为:const blog = options,
可以在 vue.js 源码,第 243 行,写入一个 debugger;运行之后,很明显调用了该方法,vue 底层在 components 里面进行了判断
组件的嵌套
<div id="root"></div>
<script type="text/javascript">
// 定义 student 组件
const student = Vue.extend({
name: "student",
template: `
<div>
<h2>同学姓名:{{name}}</h2>
<h2>同学年龄:{{age}}</h2>
</div>
`,
data() {
return {
name: "星宿君",
age: 18,
};
},
});
// 定义 blog 组件
const blog = Vue.extend({
name: "blog",
template: `
<div>
<h2>博客名称:{{name}}</h2>
<h2>博客地址:{{address}}</h2>
<student></student>
</div>
`,
data() {
return {
name: "星宿君 の Blog",
address: "https://blog.huxinfeng.com",
};
},
// 注册组件(局部)
components: {
student,
},
});
// 定义 hello 组件
const hello = Vue.extend({
template: `<h1>{{msg}}</h1>`,
data() {
return {
msg: "欢迎来访星宿君 の Blog!",
};
},
});
// 定义 app 组件
const app = Vue.extend({
template: `
<div>
<hello></hello>
<blog></blog>
</div>
`,
components: {
blog,
hello,
},
});
// 创建 vm
new Vue({
el: "#root",
template: "<app></app>",
// 注册组件(局部)
components: { app },
});
</script>
VueComponent
<div id="root">
<blog></blog>
<hello></hello>
</div>
<script type="text/javascript">
// 定义 blog 组件
const blog = Vue.extend({
name: "blog",
template: `
<div>
<h2>博客名称:{{name}}</h2>
<h2>博客地址:{{address}}</h2>
<button @click="showName">点我提示博客名</button>
</div>
`,
data() {
return {
name: "星宿君 の Blog",
address: "https://blog.huxinfeng.com",
};
},
methods: {
showName() {
console.log("showName", this);
},
},
});
const test = Vue.extend({
template: `<span>星宿君</span>`,
});
// 定义 hello 组件
const hello = Vue.extend({
template: `
<div>
<h2>{{msg}}</h2>
<test></test>
</div>
`,
data() {
return {
msg: "你好啊!",
};
},
components: { test },
});
// console.log('@',blog)
// console.log('#',hello)
// 创建 vm
const vm = new Vue({
el: "#root",
components: { blog, hello },
});
</script>
Vue.extend 源码分析
Vue.extend = function (extendOptions) {
/* .......... */
var Sub = function VueComponent(options) {
this._init(options);
};
/* .......... */
return Sub;
};
小结
关于 VueComponent:
- blog 组件本质是一个名为 VueComponent 的构造函数,且不是程序员定义的,是 Vue.extend 生成的。
- 我们只需要写
或 ,Vue 解析时会帮我们创建 blog 组件的实例对象,
即 Vue 帮我们执行的:new VueComponent(options)。 - 特别注意:每次调用 Vue.extend,返回的都是一个全新的 VueComponent!!!!,见上面 Vue.extend 源码分析
- 关于 this 指向:
(1) 组件配置中:
data 函数、methods 中的函数、watch 中的函数、computed 中的函数 它们的 this 均是【VueComponent 实例对象】。
(2) new Vue(options)配置中:
data 函数、methods 中的函数、watch 中的函数、computed 中的函数 它们的 this 均是【Vue 实例对象】。 - VueComponent 的实例对象,以后简称 vc(也可称之为:组件实例对象)。
Vue 的实例对象,以后简称 vm。
一个重要的内置关系
<div id="root">
<blog></blog>
</div>
<script type="text/javascript">
Vue.prototype.x = 99;
// 定义 blog 组件
const blog = Vue.extend({
name: "blog",
template: `
<div>
<h2>博客名称:{{name}}</h2>
<h2>博客地址:{{address}}</h2>
<button @click="showX">点我输出x</button>
</div>
`,
data() {
return {
name: "星宿君 の Blog",
address: "https://blog.huxinfeng.com",
};
},
methods: {
showX() {
console.log(this.x);
},
},
});
// 创建一个 vm
const vm = new Vue({
el: "#root",
data: {
msg: "你好",
},
components: { blog },
});
// 定义一个构造函数
/* function Demo(){
this.a = 1
this.b = 2
}
// 创建一个 Demo 的实例对象
const d = new Demo()
console.log(Demo.prototype) // 显示原型属性
console.log(d.__proto__) // 隐式原型属性
console.log(Demo.prototype === d.__proto__)
// 程序员通过显示原型属性操作原型对象,追加一个 x 属性,值为99
Demo.prototype.x = 99
console.log('@',d) */
</script>
小结
- 一个重要的内置关系:VueComponent.prototype.proto === Vue.prototype
- 为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue 原型上的属性、方法。
Comments NOTHING