目录
一个正常的后台管理界面分为顶部、导航、内容、底部,这需要一个整体的html文件,这四部分分别需要单独的css来美化,为了更好的交互还需要单独的四块JS并引入。

此时又出现一个具有顶部、内容、底部的界面,传统方式需要将原HTML中的顶部和底部复制一份,并引入原css和js,内容部分(商品列表)需要自己写,并引入新的css/js。

首先分析页面有几大块功能,例如下图有四块,比如顶部他有自己的css/js,就单独分离出来一个header组件,组建中包含实现这一功能的样式、结构、交互,其中html只写了他这一个片段。

组件更强的功能是复用,如果别的地方也想要用相同的组件只需要一句话引用,新的界面再自己写即可。


1. 理解: 向外提供特定功能的 js 程序, 一般就是一个 js 文件
2. 为什么: js 文件很多很复杂
3. 作用: 复用 js, 简化 js 的编写, 提高 js 运行效率
1. 理解: 用来实现局部(特定)功能效果的代码集合(html/css/js/image…..)
2. 为什么: 一个界面的功能很复杂
3. 作用: 复用编码, 简化项目编码, 提高运行效率
当应用中的 js 都以模块来编写的, 那这个应用就是一个模块化的应用。
当应用中的功能都是多组件的方式来编写的, 那这个应用就是一个组件化的应用。
对非单文件组件和单文件组件的理解:
非单文件组件:
单文件组件:一个组件和一个文件是对应的
真正的vue开发大多用的单文件组件,条理清晰,易于维护。
Vue中使用组件的三大步骤:
一、定义组件(创建组件)
传统创建vm:

创建组件需要使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但是还是有两点不一样:
1.el不要写 ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
2.data必须写成函数 ———— 避免组件被复用时,数据存在引用关系。
写成一个函数返回一个对象,当修改某一个对象值的时候,不影响另一个对象。
受影响的情况(浅拷贝,指向同一个内存地址,堆内存):
不受影响的情况:
第一种是共用一套,第二种是各自返回一套
函数返回的对象相当于重新创建
函数每次调用都新开一个空间,然后返回一个对象,就有独立性

school组件如下:

还需要有html结构(最基本),使用template定义:
- //第一步:创建school组件
- const school = Vue.extend({
- template:`
-
-
学校名称:{{schoolName}}
-
学校地址:{{address}}
-
-
- `,
- // el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
- data(){
- return {
- schoolName:'尚硅谷',
- address:'北京昌平'
- }
- },
- methods: {
- showName(){
- alert(this.schoolName)
- }
- },
- })
二、注册组件
全局注册组件
- //全局注册组件
- Vue.component('hello',hello)
局部注组件
- //创建vm
- new Vue({
- el:'#root',
- data:{
- msg:'你好啊!'
- },
- //第二步:注册组件(局部注册)
- components:{
- school,
- student
- }
- })
1.局部注册:靠new Vue的时候传入components选项
2.全局注册:靠Vue.component('组件名',组件)
三、使用组件(写组件标签)


一个组件使用多次,数据是不被影响的。
1.关于组件名:
一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
多个单词组成:
第一种写法(kebab-case命名):my-school
第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
备注:
(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
(2).可以使用name配置项指定组件在开发者工具中呈现的名字。
2.关于组件标签:
第一种写法:
第二种写法:
备注:不用使用脚手架时,

只显示一个

3.一个简写方式:
const school = Vue.extend(options) 可简写为:const school = options
直接写配置项:

注册的时候是什么名字,用的时候就是什么名字

父子组件

eg:Students注册到School里面,并在template中使用(注册给谁就在谁的结构中写),前提是student需要在school之前定义。

school注册在vm,student注册在school


app管理所有的组件,定义时需要将其他组件添加进来,其中student无需再添加,因为student已经添加到school里面了。

此时在vm里只需注册app即可。(app:一人(vm)之下,万人之上)

- html>
- <html>
- <head>
- <meta charset="UTF-8" />
- <title>组件的嵌套title>
-
- <script type="text/javascript" src="../js/vue.js">script>
- head>
- <body>
-
- <div id="root">
-
- div>
- body>
-
- <script type="text/javascript">
- Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
-
- //定义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组件
- 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>
- html>
1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
输出这个组件

组件本质上就是这个构造函数

2.我们只需要写
3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
eg:张三有个弟弟叫张四,他俩不是同一个人。
每一次使用extend函数都会调用VueComponent函数,在这个函数里会返回sub,这个sub都是现定义的,然后再返回,并不是共用一个VueCommponet()。
4.关于this指向:
(1).组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
打印this


(2).new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。Vue的实例对象,以后简称vm。
大哥是vm,下属管理两个弟弟,一个是school组件,一个是hello组件
组件中的子组件
完整代码:
- html>
- <html>
- <head>
- <meta charset="UTF-8" />
- <title>一个重要的内置关系title>
-
- <script type="text/javascript" src="../js/vue.js">script>
- head>
- <body>
-
-
- <div id="root">
- <school>school>
- div>
- body>
-
- <script type="text/javascript">
- Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
- Vue.prototype.x = 99
-
- //定义school组件
- const school = Vue.extend({
- name:'school',
- template:`
-
-
学校名称:{{name}}
-
学校地址:{{address}}
-
-
- `,
- data(){
- return {
- name:'尚硅谷',
- address:'北京'
- }
- },
- methods: {
- showX(){
- console.log(this.x)
- }
- },
- })
-
- //创建一个vm
- const vm = new Vue({
- el:'#root',
- data:{
- msg:'你好'
- },
- components:{school}
- })
-
-
- //定义一个构造函数
- /* 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>
- html>

一个重要的内置关系
VueComponent.prototype.__proto__ === Vue.prototype
让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
一个例子
一个构造函数的显示原型属性和一个对象的隐式原型属性都指向原型对象。
通过Demo的显示原型属性触碰到原型对象,再顺着这条线获取到d的隐式原型对象
- //程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
- Demo.prototype.x = 99
- console.log('@',d.__proto__.x) //99
实例的隐式原型属性,永远指向自己缔造者的原型对象,如下图所示。

对VueCompent()构造函数:
但是Vue做了这么一件事:
Vue让VueCompent的原型对象的隐式原型属性指向了Vue的原型对象。


完整代码:
- html>
- <html>
- <head>
- <meta charset="UTF-8" />
- <title>一个重要的内置关系title>
-
- <script type="text/javascript" src="../js/vue.js">script>
- head>
- <body>
-
-
- <div id="root">
- <school>school>
- div>
- body>
-
- <script type="text/javascript">
- Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
- Vue.prototype.x = 99
-
- //定义school组件
- const school = Vue.extend({
- name:'school',
- template:`
-
-
学校名称:{{name}}
-
学校地址:{{address}}
-
-
- `,
- data(){
- return {
- name:'尚硅谷',
- address:'北京'
- }
- },
- methods: {
- showX(){
- console.log(this.x)
- }
- },
- })
-
- //创建一个vm
- const vm = new Vue({
- el:'#root',
- data:{
- msg:'你好'
- },
- components:{school}
- })
-
-
- //定义一个构造函数
- /* 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) //99
- */
-
- script>
- html>
非单文件组件有个弊病,样式不能跟着组件走。
一个.vue 文件的组成(3 个部分)
1. 模板页面

2. JS 模块对象

3. 样式


注意:

需要使用默认暴露

还可以再精简一点,去除中间变量

还可以再精简一点,Vue.extend可以省略。其中name最好和文件名保持一致。

Student.vue
- <template>
- <div>
- <h2>学生姓名:{{name}}h2>
- <h2>学生年龄:{{age}}h2>
- div>
- template>
-
- <script>
- export default {
- name:'Student',
- data(){
- return {
- name:'张三',
- age:18
- }
- }
- }
- script>
School.vue
- <template>
- <div class="demo">
- <h2>学校名称:{{name}}h2>
- <h2>学校地址:{{address}}h2>
- <button @click="showName">点我提示学校名button>
- div>
- template>
-
- <script>
- export default {
- name:'School',
- data(){
- return {
- name:'尚硅谷',
- address:'北京昌平'
- }
- },
- methods: {
- showName(){
- alert(this.name)
- }
- },
- }
- script>
-
- <style>
- .demo{
- background-color: orange;
- }
- style>
App.vue(汇总所有的组件,所以需要引入组件,并注册)
- <template>
- <div>
- <School>School>
- <Student>Student>
- div>
- template>
-
- <script>
- //引入组件
- import School from './School.vue'
- import Student from './Student.vue'
-
- export default {
- name:'App',
- components:{
- School,
- Student
- }
- }
- script>
所有的组件都得听从vm,所以得创建vm
main.js 在这里创建vm,且只有app.vue才有资格与之对话。首先需要引入。记得加入template
- import App from './App.vue'
-
- new Vue({
- el:'#root',
- template:`
`, - components:{App},
- })
index.html 创造容器
- html>
- <html>
- <head>
- <meta charset="UTF-8" />
- <title>练习一下单文件组件的语法title>
- head>
- <body>
-
- <div id="root">div>
-
-
- body>
- html>
总结;
template里面写结构,script里面写脚本,脚本包含给组件命名,配置数据,配置计算属性。
style配置样式,app组件汇总组件,main.js创建vue实例,并且指明为哪个容器服务。