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>