二、 Vue组件化编程
2.1 组件化模式与传统方式编写应用做对比:
传统方式编写应用
依赖关系混乱,不好维护:例如:比如需要引入js1,js2,js3,但是js3需要用到js1、2的方法,所以js1、2要先引入,而js2的使用需要用到js1中的方法,也就是js1需要在js2前面引用,三个我们还能分清先后顺序,可是多了就会混乱。
2.代码复用率不高
两个html,相同的底部和顶部结构,先创建html1,在创建html2时,是复制了html1的,不属于代码复用;此时,如果将相同结构包装在同一段html结构中,用innerHTML来实现代码复用,这一块我也不太明白,死记硬背吧,就是封装相同的也不好用!
使用组件化方式优势:
模块 庞大js 模块指js模块
模块化 a.js b,js 庞大js给拆了 按照模块化的标准拆开
组件 :不同的功能点不同的组件
2.2 非单文件组件
小tips 使用函数式和对象式改变数据的方法 :
作用:通过分析函数式和对象式的区别,才能知道组件中创建组件时里面的data数据使用函数式的原因了。同一个data数据,但是调用时有不同的实例 互相不会干扰
// 使用对象式和函数式的区别
// let data = {
// a: 1,
// b: 2
// }
function data () {
return {
a: 1,
b: 2
}
}
// 使用对象式一变都变 根据栈堆存放
// const x1 = data
// const x2 = data
// 当你使用函数来返回对象时,每次调用该函数都会创建一个新的对象实例。即使这些对象具有相同的结构和初始值,
//它们也是不同的对象,存储在内存的不同位置。因此,修改一个对象不会影响其他通过该函数创建的对象。
const x1 = data()
const x2 = data()
> > Vue中使用组件的三大步骤:
> > 一、定义组件(创建组件)
> > 二、注册组件
> > 三、使用组件(写组件标签) 一、如何定义一个组件?
> > 使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,
> 但也有点区别:
> > 1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器
> > 2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
> > 备注:使用template可以配置组件结构。
> > 二、如何注册组件?
> > 1.局部注册:靠new Vue的时候传入components选项
> > 2.全局注册:靠Vue.component('组件名',组件)
> > 三、编写组件标签:<school></school>
下面这段代码主要是讲述组件标签三步骤,以及创建局部组件和全局组件。主要式在注册那一块的差别!
<!--准备好一个容器 -->
<div id="root">
<h1>{{msg}}</h1>
<hr>
<!-- 第三步:编写组件标签 -->
<school></school>
<hr>
<!-- 第三步:编写组件标签 -->
<student></student>
<!-- 实现复用 并且因为data函数实现改变数据互不干扰
-->
<school></school>
<student></student>
</div>
<!-- 第二个容器使用第一个容器的组件 -->
<div id="root2">
<school></school>
组件标签
<hello></hello>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
// 第一步:创建school组件
const school = Vue.extend({
// el: '#root',//组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器
template: `<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click='showName'>点我提示学校名</button>
</div>
`,
data () {
return {
schoolName: '尚硅谷',
address: '北京昌平',
}
}, methods: {
showName () {
alert(this.schoolName)
}
},
})
//第一步:创建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)
//第二步:注册组件(局部注册)
new Vue({
el: '#root',
data: {
msg: '你好啊'
},
components: {
school,
student
}
})
new Vue({
el: '#root2',
components: {
school
}
})
// // 使用对象式和函数式的区别
// // let data = {
// // a: 1,
// // b: 2
// // }
// function data () {
// return {
// a: 1,
// b: 2
// }
// }
// // 使用对象式一变都变 根据栈堆存放
// // const x1 = data
// // const x2 = data
// // 当你使用函数来返回对象时,每次调用该函数都会创建一个新的对象实例。即使这些对象具有相同的结构和初始值,
//它们也是不同的对象,存储在内存的不同位置。因此,修改一个对象不会影响其他通过该函数创建的对象。
// const x1 = data()
// const x2 = data()
</script>
几个注意点
<!--准备好一个容器 -->
<div id="root">
<h2>{{msg}}</h2>
<!-- 双标签 -->
<!-- <school></school> -->
<!-- <School></School> -->
<!-- <my-school></my-school> -->
<!-- <MySchool></MySchool> -->
<!-- 单标签 自闭合 但是写多个只展示一个 所以建议在脚手架中适合用-->
<school />
<school />
<school />
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//定义组件
const s = Vue.extend({
// 也可以组件注册为一个名字 Vue开发工具展示的一个名字 也就是给Vue开发工具那一块特意起了一个名字
name: 'atguigu',
template: `
<div>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
`,
data () {
return {
name: '尚硅谷',
address: '北京'
}
}
})
// // 使用extend定义组件简写
// const s = {
// // 也可以组件注册为一个名字 Vue开发工具展示的一个名字 也就是给Vue开发工具那一块特意起了一个名字
// name: 'atguigu',
// template: `
// <div>
// <h2>学校名称:{{name}}</h2>
// <h2>学校地址:{{address}}</h2>
// </div>
// `,
// data () {
// return {
// name: '尚硅谷',
// address: '北京'
// }
// }
// }
new Vue({
el: '#root',
data: {
msg: '欢迎学习Vue!'
},
components: {
// 第一种写法(首字母小写):school 但是Vue开发工具会默认转化为首字母大写
school: s
// 组件名字跟组件标签要相同
// School: s
// 'my-school': s
// 在脚手架中才可以接收大驼峰命名
// MySchool: s
}
})
</script>
总结:
几个注意点:
1.关于组件名:
一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
多个单词组成:
第一种写法(kebab-case命名):my-school
第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
备注:
(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
(2).可以使用name配置项指定组件在开发者工具中呈现的名字。
2.关于组件标签:
第一种写法:<school></school>
第二种写法:<school/>
备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。
3.一个简写方式:
const school = Vue.extend(options) 可简写为:const school = options
一人之下 万人之上组件app
补充知识:在模板容器中没有写代码的原理 根据生命周期原理图,给换成内部模板了
<!--准备好一个容器 -->
<div id="root">
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
// 定义school的子组件student
const student = Vue.extend({
name: 'student',
template: `
<div>
<h2>学生姓名:{{name}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
`,
data () {
return {
name: '尚硅谷',
age: 18
}
}
})
//定义school组件
const school = Vue.extend({
name: 'school',
template: `
<div>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<student></student>
</div>
`,
data () {
return {
name: '尚硅谷',
address: '北京'
}
},
components: {
student
}
})
//定义hello组件
const hello = Vue.extend({
template: `<h1>{{msg}}</h1>`,
data () {
return {
msg: '欢迎来到尚硅谷学习!'
}
}
})
//定义app组件 相当于所有组建的管理者 也就是vm委派给app 让app管理所有组件
const app = Vue.extend({
template: `
<div>
<hello></hello>
<school></school>
</div>
`,
components: {
school,
hello
}
})
//创建vm
new Vue({
template: `<app></app>`,
el: '#root',
//注册组件(局部)
components: {
app
}
})
</script>
VueComponent
总结来说:就是VueComponent就是类比于Vue,所以有实例对象vc 在组件中this指向VueComponent实例对象,也就是组件
下面案例中涉及到组件嵌套
总结
关于VueComponent:
1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
2.我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,
即Vue帮我们执行的:new VueComponent(options)。
3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
4.关于this指向:
(1).组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】
(2).new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】
5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
Vue的实例对象,以后简称vm。
<!--准备好一个容器 -->
<div id="root">
<school></school>
<hello></hello>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//定义school组件
const school = Vue.extend({
name: 'school',
template: `
<div>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName">点我提示学校名</button>
</div>
`,
data () {
return {
name: '尚硅谷',
address: '北京'
}
}, methods: {
showName () {
// 组件中的this指向VueComponent,并且里面有Vue中的很多相似数据,进行了数据代理
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 }
})
// 对应的VueComponent不是同一个
// school.a = 100
// console.log('@', school.a)
// console.log('#', hello.a)
// console.log('@', school)
// console.log('#', hello)
const vm = new Vue({
el: '#root',
components: {
school, hello
}
});
</script>
补充知识:上文提到望函数中添加属性,直接函数点属性名即可,因为函数在某种意义上也是对象。
<SCRIPT>
function aa () {
console.log('哈哈哈')
}
aa.b = 100
// 函数本身也是一个对象
console.log(aa.b);
</SCRIPT>
一个重要的内置关系
1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
<div id="root">
<!-- 相当于new Component() -->
<school></school>
</div>
<script>
Vue.prototype.x = 99
//定义school组件
const school = Vue.extend({
template: `
<div>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click='showX'>点我发现我能get到Vue原型对象中的x</button>
</div>`,
data () {
return {
name: '尚硅谷',
address: '北京'
}
}, methods: {
showX () {
console.log(this.x)
}
}
})
//创建一个vm
const vm = new Vue({
el: '#root',
data: {
msg: '你好'
}, components: {
school
}
})
// 不要写VueComponent 死记硬背:我们通过调用extend函数返回值VueComponent并且赋值给school
//这里按理说应该是true 但是不知道怎么回事是false
console.log(school.prototype._proto_ === Vue.prototype)
/* 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._proto_.x)
// 缩写
console.log, ('@', d.x)
// 表示关于demo函数的实例对象
console.log(d); */
</script>
组件实例对象小型vm 他的data必须写成函数式,也不能配置el
2.3 单文件组件
首先是xxx.vue,不能直接展示在浏览器,需要编译成js文件
方法1:使用webpack
方法2:使用脚手架
命名类似于组件名称 推荐首字母大写或者大驼峰命名
安装插件 识别vue文件
vue文件的编写依据组件的定义:实现应用中局部功能的代码和资源的集合,包括html结构、css样式、js交互
书写顺序
在②中通过如下将组件引入:
现成代码见资源