非单文件组件(过渡)
非单文件组件就是指并非一个组件占用一个文件,而是一个人间中有多个组件。我们只将其作为学习的过度,实际开发中不适用这种方式。
demo:
<body>
<div id="app">
<h1>大哥</h1>
<hr>
<!-- 3. 使用组件 -->
<xuexiao></xuexiao>
<hr>
<student></student>
</div>
</body>
<script src="https://cdn.jsdelivr.net/gh/brokyz/brokyzCDN/vue/2.7.10/vue.js"></script>
<script>
// 1. 创建组件
// 组件中不用指定el,因为组件不用绑定死为谁服务,追随vm实例。
// 组件中的数据必须以函数的形式赋值。
const school = Vue.extend({
// 书写组件的html
template: `
<div>
<h2>school:{{name}}</h2>
</div>
`,
data() {
return {
name: "首经贸"
}
}
})
// 创建组件的简写形式,直接用对象。
const student = {
template: `
<div>
<h2>student:{{name}}</h2>
</div>
`,
data() {
return {
name: "brokyz"
}
}
}
const vm = new Vue({
// 2. 注册组件
components: {
xuexiao: school, // 可以注册名和组件名相同直接简写成 school
student,
},
}).$mount("#app")
</script>
使用组件一般分为三步:
- 创建组件:此时组件已经创建,但是还没有被 vm 实例注册使用。
- 注册组件:此时组件被 vm 实例注册,但是并没有被 vm 实例使用。
- 编写组件标签(使用组件):此时组件被 vm 实例使用。
组件中不能指定 el 或者 mount:
由于组件是灵活的可复用的,所以并不需要绑定一个元素只为其服务。而是由注册该组件的 vm 实例来决定一起为谁服务。
可以将 vm 实例理解成大哥,组件是加入大哥麾下的小弟。大哥说打哪小弟也跟着打哪。
所有的组件都得有大哥才可以展现出来。
组件中必须以函数的形式来指定数据:
因为在同一个文件下,如果以对象的形式来指定数据的话,那么多个组件指向的是同一个对象。这样组件之间的数据就比较混乱。
demo:
let data = {
name: "brokyz"
}
let a = data
let b = data
// 此时 a 和 b 指向了同一个 data,a 和 b 将操作同一个对象。
data(){
return {
name: "brokyz"
}
}
let a = data()
let b = data()
// 此时 a 和 b 之前指向的是不同的对象。
组件的结构将以 template 的形式赋予组件。
组件的命名
在组件中指定 name 配置项,那么不管注册的时候是什么名字,在 Vue 开发者工具中都会显示组件指定的 name。
const school = Vue.extend({
// 指定组件的名字
name: "myschool",
// 书写组件的html
template: `
<div>
<h2>school:{{name}}</h2>
</div>
`,
data() {
return {
name: "首经贸"
}
}
})
组件注册时的命名规范:
- 单个单词全小写
school: school
:在 Vue 开发者工具中首字母会自动大写显示。School
- 单个单词首字母大写
School: school
:与 Vue 开发者工具风格一致。School
- 多个单词用 - 隔开
'my-school': school
:注册时要用引号包裹,在开发者工具中以大驼峰的形式显示。MySchool
- 多个单词首字母大写
MySchool: school
:只有在使用脚手架的时候才能这样命名,否则组件无效。MySchool
组件嵌套
可以在组件上使用另一个组件,但是在非单个文件时注意书写顺序,需要用的组件要先创建。
<body>
<div id="app">
<h1>大哥</h1>
<hr>
<!-- 3. 使用组件 -->
<xuexiao></xuexiao>
<hr>
<student></student>
</div>
</body>
<script src="https://cdn.jsdelivr.net/gh/brokyz/brokyzCDN/vue/2.7.10/vue.js"></script>
<script>
// 1. 创建组件
// 组件中不用指定el,因为组件不用绑定死为谁服务,追随vm实例。
// 组件中的数据必须以函数的形式赋值。
const student = Vue.extend({
template: `
<div>
<h2>student:{{name}}</h2>
</div>
`,
data() {
return {
name: "brokyz"
}
}
})
const school = Vue.extend({
// 书写组件的html
name: "myschool",
template: `
<div>
<h2>school:{{name}}</h2>
<student></student>
</div>
`,
data() {
return {
name: "首经贸"
}
},
components: {
student
}
})
const vm = new Vue({
// 2. 注册组件
components: {
xuexiao: school, // 可以注册名和组件名相同直接简写成 school
student,
},
}).$mount("#app")
</script>
app 组件
在开发中,会定义一个 app 组件,用于管理应用中的所有组件。可以将 app 理解为一人之下(root),万人之上(其他组件)。
<body>
<div id="root">
<app></app>
</div>
</body>
<script src="https://cdn.jsdelivr.net/gh/brokyz/brokyzCDN/vue/2.7.10/vue.js"></script>
<script>
// 1. 创建组件
// 组件中不用指定el,因为组件不用绑定死为谁服务,追随vm实例。
// 组件中的数据必须以函数的形式赋值。
const student = Vue.extend({
template: `
<div>
<h2>student:{{name}}</h2>
</div>
`,
data() {
return {
name: "brokyz"
}
}
})
const school = Vue.extend({
// 书写组件的html
name: "myschool",
template: `
<div>
<h2>school:{{name}}</h2>
<student></student>
</div>
`,
data() {
return {
name: "首经贸"
}
},
components: {
student
}
})
const app = Vue.extend({
template: `
<div>
<school></school>
</div>
`,
components: {
school
}
})
const vm = new Vue({
// 2. 注册组件
components: {
app
},
}).$mount("#root")
</script>
VueComponent 构造函数
-
创建组件的本质就是创建一个名为 VueComponent 的构造函数,这不是程序员自己定义的,而是由
Vue.extend
帮我们生成的。 -
我们只需要写
<school/>
或<school><school/>
,Vue 解析时会帮我们创建 school 组件的实例对象,即 Vue 帮我们执行的:new VueComponent(options)
。 -
特别注意:每次调用
Vue.extend
,返回的都是一个全新的 VueComponent!!! -
关于 this 的指向:
-
组件配置中:
data函数、methos中的函数、watch中的函数、computed中的函数,它们的 this 全指向【VueComponent 实例对象】。
-
new Vue(options) 中:
data函数、methos中的函数、watch中的函数、computed中的函数,它们的 this 全指向【Vue 实例对象】。
-
-
VueComponent 的实例对象,也称为 vc 或 组件实例对象,Vue 实例对象,简称 vm。
-
vm.$children
或vc.$children
都存储了它们里面的组件。
vm 与 vc 的内置关系
首先从表面上说,vm 需要 el,而且 data 可以是对象可以是函数。而 vc 没有 el,必须是函数 data。
然后观察其二者的原型关系:
注意:实例对象的__proto__
是隐式原型属性,构造函数的prototype
式显示原型属性,二者都同时指向原型对象。一般我们用显示进行操作,隐式进行使用。
单文件组件
推荐 vscode 插件:vetur
组件 school.vue
<template>
<div class="demo">
<h2>学校名称:{{ name }}</h2>
<h2>学校地址:{{ address }}</h2>
</div>
</template>
<script>
export default {
data() {
return {
name: '首经贸',
address: '北京市丰台区'
};
}
};
</script>
<style>
.demo {
background-color: orange;
}
</style>
向外暴露组件:
我们这里的单文件的组件是需要被其他人导入并且注册的,所以我们这里要向外暴露我们的 vc。
// Vue 推荐的简写写法
export default {
data() {
return {
name: '首经贸',
address: '北京市丰台区'
};
}
};
// 上一种写完整
const school = Vue.extend({
data() {
return {
name: '首经贸',
address: '北京市丰台区'
};
}
})
export default school
app.vue
<template>
<div>
<School></School>
<student></student>
</div>
</template>
<script>
// 引入组件
import School from './school'
export default {
name: 'App',
components: {
School
}
};
</script>
<style></style>
main.js
import App from './App.vue'
new Vue({
el: '#root',
template: '<app></app>',
components: {
App
},
})
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="root"></div>
<script src="https://cdn.jsdelivr.net/gh/brokyz/brokyzCDN/vue/2.7.10/vue.js"></script>
<script src="./main.js"></script>
</body>
</html>
- 引入 main.js 要在容器的下面才可以。
- 需要在这里引入 vue.js。
注意:这里都配置完成后,页面中并不能显示出来,需要在脚手架中才可以运行。
VueCli 脚手架
脚手架可以为我们自动配置我们的前端工程化的开发环境,省去了我们使用 webpack 手动配置前端工程化开发环境的麻烦。
使用
安装 VueCli
npm install -g @vue/cli
切换到要创建项目的目录,然后使用命令创建项目
vue create projectNmae
如果下载慢需要配置淘宝镜像
npm config set registry https://registry.npm.taobao.org
开发时编译代码
npm run serve
分析脚手架结构
配置文件:
- .gitignore:git 的忽略文件。
- babel.config.js:babel 的配置文件,用于 es6 转 es5。
- package.json:nodejs的配置文件。
- package-lock.json:nodejs中的包的版本控制文件,里面存着报的版本信息。
主题文件:
- src/main.js:vue 项目中一切的开端,整个项目的入口文件。文件中导入了 vue 和 app,创建了 vm 实例。
- src/App.vue:项目中的一个汇总组件,所有的组件展示都汇总到这里,它是所有组件的父组件。然后再由 vm 实例调用 App 总组件进行页面展现。
- src/components:用于存放组件。
- src/assets:用于存放静态文件。
- public/index.html:vm 实例最终渲染的页面,其中有元素被 vm 实例绑定。
render 函数
我们认识脚手架之前的 vm 实例:
import Vue from 'vue'
import App from './App.vue'
new Vue({
template: '<App></App>',
components: {App}
}).$mount('#app')
上述这种 vm 实例的写法在脚手架中运行时会报错。因为在脚手架中导入的 vue 并不是完整路径,而是 vue 文件夹,其中包含了许多版本的 vue 文件,但是默认为我们导入的是 dist/vue.runtime.esm.js, 这是精简掉了模板解析器的 vue,并不是完成版的 vue.js。这个由于没有 模板解析器,所以无法解析 template 中的语法。
这时我们就可以使用 render 渲染函数:
import Vue from 'vue'
import App from './App.vue'
new Vue({
render(createElement){
return createElement('h1', '你好')
}
}).$mount('#app')
// 简写
new Vue({
render: h => h(App),
}).$mount('#app')
为什么 vue 会有精简版本?
vue 中有些东西是我们开发时用到的,这些东西上线时被 webpack 打包编译会生成 js。但是里面有些只有开发时会用的代码在上线时并不会被使用。所以 vue 为我们提供了一些精简版本的 vue。类似于 nodejs 中的 dependencies 和 devDependencies。
注意:
- 我们所说的模板解析器是服务于的是在 vue.js 中用于创建 vm 实例时配置项里面的 template。
- 而组件中的 tamplate 标签是我们 nodejs 中安装的 vue-template-compiler 包来进行解析的。
关于不同版本 vue 的区别:
-
vue.js 于 vue.runtime.xxx.js 的区别:
- vue.js 是完整版,包含了:核心功能+模板解析器。
- vue.runtime.xxx.js 是运行版的 Vue,只包含:核心功能,不包含模板解析器。
-
因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 配置项,需要使用 render 函数接收到的 createElement 函数去指定具体内容。