23-Vue组件化编程-非单文件组件
非单文件组件
一个文件中包含有n个组件
非单文件组件的特点
1)模板编写没有提示
2)没有构建过程,无法将ES6转换成ES5
3)不支持组件的CSS
4)真正开发中几乎不用
Vue中使用组件的三大步骤
1. 定义组件(也就是创建组件)
2. 注册组件(这里有局部注册和全局注册)
3. 使用组件(编写组件标签)
注册组件(局部注册)
靠new Vue的时候传入components选项
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>基本使用</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<!--<h2>学校名称:{{schoolName}}</h2>-->
<!--<h2>学校名称:{{address}}</h2>-->
<!--第三步:编写学校组件标签-->
<xuexiao></xuexiao>
<hr>
<!--<h2>学生姓名:{{studentName}}</h2>-->
<!--<h2>学生年龄:{{age}}</h2>-->
<!--第三步:编写学生组件标签-->
<xuesheng></xuesheng>
</div>
<script type="text/javascript">
// 阻止 vue 在启动时生成生产提示
Vue.config.productionTip = false
// 第一步:创建school组件
const school = Vue.extend({
// 这里需要注意,组件定义时一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪一个容器
// el:"#root",
template:'<div>' +
'<h2>学校名称:{{schoolName}}</h2>' +
'<h2>学校名称:{{address}}</h2>' +
'</div>',
// 在组件的使用中,data必须使用以下的函数式写法,否则会报错
data(){
return {
schoolName:"东华理工大学",
address:"江西南昌"
}
}
})
// 第一步:创建student组件
const student = Vue.extend({
template:'<div>' +
'<h2>学生姓名:{{studentName}}</h2>' +
'<h2>学生年龄:{{age}}</h2>' +
'</div>',
data(){
return {
studentName:"马铃薯",
age:26
}
}
})
// 创建vm
new Vue({
el:"#root",
// data(){
// return{
// schoolName:"东华理工大学",
// address:"江西南昌",
// studentName:"马铃薯",
// age:26
// }
// }
// 第二步:注册组件(局部注册)
components:{
xuexiao:school,
xuesheng:student
}
})
</script>
</body>
</html>

注册组件(全局注册)
靠Vue.component("组件名",组件)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>基本使用</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<!--第三步:编写hello组件标签-->
<hello></hello>
</div>
<script type="text/javascript">
// 阻止 vue 在启动时生成生产提示
Vue.config.productionTip = false
// 第一步:创建hello组件
const hello = Vue.extend({
// 这里需要注意,组件定义时一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪一个容器
// el:"#root",
template:'<div>' +
'<h2>你好啊,{{name}}</h2>' +
'</div>',
// 在组件的使用中,data必须使用以下的函数式写法,否则会报错
data(){
return {
name:"好久不见!"
}
}
})
// 第二步:注册组件(全局注册)
Vue.component("hello",hello)
// 创建vm
new Vue({
el:"#root",
})
</script>
</body>
</html>

组件名的注意事项
一个单词组成:
1)第一种写法(首字母小写):school
2)第二种写法(首字母大写):School
多个单词组成:
1)第一种写法(kebab-case命名):my-school
2)第二种写法(CamelCase命名):MySchool(这里需要Vue脚手架支持)
备注:
1)组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行
2)可以使用name配置项指定组件在开发者工具中呈现的名字
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>几个注意点</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<h1>{{msg}}</h1>
<!--第三步:使用组件标签-->
<!--<School></School>-->
<my-school></my-school>
</div>
<script type="text/javascript">
// 阻止 vue 在启动时生成生产提示
Vue.config.productionTip = false
// 第一步:创建组件
const school = Vue.extend({
// 可以使用name配置项,指定组件在开发者工具中呈现的名字
// 也就是说,只要使用了name配置项,不管注册组件时使用的名字是什么,组件在开发者工具中的名字都为Malingshu
name:"malingshu",
template:"<div>" +
"<h2>学校名称:{{schoolName}}</h2>" +
"<h2>学校地址:{{address}}</h2>" +
"</div>",
data(){
return{
schoolName:"东华理工大学",
address:"江西南昌"
}
}
})
new Vue({
el:"#root",
data(){
return{
msg:"欢迎来到马铃薯的学习空间!"
}
},
// 第二步:注册组件(局部注册)
components:{
// School:school,
"my-school":school // 组件在开发者工具中的名字为 MySchool
}
})
</script>
</body>
</html>

组件标签的注意事项
1)第一种写法:<school></school>
2)第二种写法:< school/> (这里需要Vue脚手架支持)
备注:
不实用脚手架时,<school/>会导致后续组件不能渲染
一个简写方式
const school = Vue.extend(options) 可简写为:const school = options
这是因为父组件components引入的时候会自动创建
// 创建组件 const school = Vue.extend({ // 可以使用name配置项,指定组件在开发者工具中呈现的名字 // 也就是说,只要使用了name配置项,不管注册组件时使用的名字是什么,组件在开发者工具中的名字都为Malingshu name:"malingshu", template:"<div>" + "<h2>学校名称:{{schoolName}}</h2>" + "<h2>学校地址:{{address}}</h2>" + "</div>", data(){ return{ schoolName:"东华理工大学", address:"江西南昌" } } }) // 简写 const school2 = { // 可以使用name配置项,指定组件在开发者工具中呈现的名字 // 也就是说,只要使用了name配置项,不管注册组件时使用的名字是什么,组件在开发者工具中的名字都为Malingshu name:"malingshu", template:"<div>" + "<h2>学校名称:{{schoolName}}</h2>" + "<h2>学校地址:{{address}}</h2>" + "</div>", data(){ return{ schoolName:"东华理工大学", address:"江西南昌" } } }
组件的嵌套
通常一个应用会以一棵嵌套的组件树的形式来组织

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件的嵌套</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<!--第三步,使用组件标签-->
<app></app>
</div>
<script type="text/javascript">
// 阻止 vue 在启动时生成生产提示
Vue.config.productionTip = false
// 第一步:创建student组件(子组件)
// 这里需要注意,子组件一定要先定义创建
const student = Vue.extend({
// 可以使用name配置项,指定组件在开发者工具中呈现的名字
// 也就是说,只要使用了name配置项,不管注册组件时使用的名字是什么,组件在开发者工具中的名字都为Malingshu
name:"student",
template:"<div>" +
"<h2>学生名字:{{studentName}}</h2>" +
"<h2>学生年龄:{{age}}</h2>"+
"</div>",
data(){
return{
studentName:"马铃薯",
age:"26"
}
}
})
// 第一步:创建school组件(父组件)
const school = Vue.extend({
// 可以使用name配置项,指定组件在开发者工具中呈现的名字
// 也就是说,只要使用了name配置项,不管注册组件时使用的名字是什么,组件在开发者工具中的名字都为Malingshu
name:"school",
template:"<div>" +
"<h2>学校名称:{{schoolName}}</h2>" +
"<h2>学校地址:{{address}}</h2>" +
"<student></student>" +
"</div>",
data(){
return{
schoolName:"东华理工大学",
address:"江西南昌"
}
},
// 注册组件(局部注册)
components:{
student:student
}
})
// 创建hello组件(与school组件平级)
const hello = Vue.extend({
template:"<h1>{{msg}}</h1>",
data(){
return{
msg:"欢迎来到马铃薯的学习空间!"
}
}
})
// 创建app组件(最外层,school与hello的父组件)
const app = Vue.extend({
template:"<div>" +
"<hello></hello>" +
"<school></school>" +
"</div>",
components:{
hello:hello,
school:school
}
})
// 创建vm
new Vue({
el:"#root",
data(){
return{
msg:"欢迎来到马铃薯的学习空间!"
}
},
// 第二步:注册组件(局部注册)
components:{
app:app,
}
})
</script>
</body>
</html>

重点:关于VueComponent
1)school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
2)我们只需要写<school/> 或 <school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)

3)特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!(重点)
关于this指向
1)组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数,它们中的this均是【VueComponent实例对象】
2)new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数,它们中的this均是【Vue实例对象】
我们为了更好的区分VueComponent和Vue,以后将VueComponent的实例对象简称vc(也可称为:组件实例对象),Vue的实例对象简称为vm。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>VueComponent</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<school></school>
<hello></hello>
</div>
<script type="text/javascript">
// 阻止 vue 在启动时生成生产提示
Vue.config.productionTip = false
// 创建school组件
const school = Vue.extend({
// 可以使用name配置项,指定组件在开发者工具中呈现的名字
// 也就是说,只要使用了name配置项,不管注册组件时使用的名字是什么,组件在开发者工具中的名字都为school
name:"school",
template:"<div>" +
"<h2>学校名称:{{schoolName}}</h2>" +
"<h2>学校地址:{{address}}</h2>" +
"<button @click='showName'>点击提示学校名称</button>" +
"</div>",
data(){
return{
schoolName:"东华理工大学",
address:"江西南昌"
}
},
methods:{
showName(){
console.log(this) // this指向VueComponent实例对象
alert(this.schoolName)
}
}
})
// 创建hello组件
const hello = Vue.extend({
name:"hello",
template:"<h2>{{msg}}</h2>",
data(){
return{
msg:"你好啊"
}
},
})
// 组件的本质是"VueComponent"构建函数
console.log("@", school)
console.log("#", hello)
// 验证,每次调用Vue.extend,返回的都是一个全新的VueComponent!!!
console.log("第一种方法:", school === hello) //false
const vm = new Vue({
el:"#root",
components:{
school:school,
hello:hello
}
})
</script>
</body>
</html>

也就是说,vm和vc是存在一个重要的内置关系的。
VueComponent.prototype.__proto__ === Vue.prototype
VueComponent的原型对象的原型对象就是Vue的原型对象,让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
扩展:显示原型(prototype)与隐式原型(proto)
函数的prototype属性:在定义函数时自动添加的,默认值时一个空Object对象
对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性
(实例的隐式原型属性,永远指向自己缔造者的原型对象)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>一个重要的内置关系</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<school></school>
</div>
<script type="text/javascript">
// 阻止 vue 在启动时生成生产提示
Vue.config.productionTip = false
// 通过显示原型属性Vue.prototype,操作Vue的原型对象,追加一个x属性,值为99
Vue.prototype.x = 99
// 创建school组件
const school = Vue.extend({
// 可以使用name配置项,指定组件在开发者工具中呈现的名字
// 也就是说,只要使用了name配置项,不管注册组件时使用的名字是什么,组件在开发者工具中的名字都为school
name:"school",
template:"<div>" +
"<h2>学校名称:{{schoolName}}</h2>" +
"<h2>学校地址:{{address}}</h2>" +
"<button @click='showX'>点击输出x</button>" +
"</div>",
data(){
return{
schoolName:"东华理工大学",
address:"江西南昌"
}
},
methods:{
showX(){
// 这里的 this 指的是 school组件的实例对象VueComponent实例对象(vc)
// 内置关系:VueComponent.prototype.__proto__ === Vue.prototype
console.log(this.__proto__.x) //99
console.log(this.x) //99
}
}
})
// 创建一个vm
new Vue({
el:"#root",
data(){
return{
msg:"你好啊"
}
},
components:{
school:school
}
})
// console.log(VueComponent.prototype.__proto__ === Vue.prototype) // 报错,这是因为VueComponent是通过Vue.exteng(options)返回给school组件
console.log(school.prototype.__proto__ === Vue.prototype) // true
// // 定义一个构造函数
// function Demo(){
// this.a = 1
// this.b = 2
// }
//
// // 创建一个Demo的实例对象
// const d = new Demo()
//
// // Demo.prototype 属性,显示原型属性
// console.log(Demo.prototype)
// // d.__proto__ 属性,隐式原型属性
// console.log(d.__proto__)
//
// // 程序员通过显示原型属性Demo.prototype,操作原型对象,追加一个x属性,值为99
// Demo.prototype.x = 99
// // 通过隐式原型属性d.__proto__,获取原型对象的x属性
// console.log("@", d.__proto__.x) //@ 99
// console.log("@", d.x) //@ 99
</script>
</body>
</html>


浙公网安备 33010602011771号