一、模块化
1.1 为什么需要模块化
没有模块化的世界:全局变量污染、难以管理的依赖。
常见的模块化标准:CommonJS(node.js)、AMD(民间)、CMD(民间)、UMD(民间)、ES6 Module(官方)
1.2 全局变量污染
新建一个test.js
文件,test.html
文件,在html中用普通方式引入js代码,代码如下
var nickname = "AlanChen";
function test(){
console.log("Hello "+nickname);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./test.js"></script>
</body>
</html>
变量nickname
和方法test
是全局的,是window全局变量,如下
1.3 模块化方式解决全局变量污染
html采用模块化的方式引入js文件,<script src="./test.js" type="module"></script>
,变量nickname
和方法test
就不再是全局的了。
1.4 模块化导出与导入
我们新建一个hello.js
文件,并用 export default
导出一个helloWorld
函数,在test.js
里import
该函数,代码如下
var helloTitle = "Hello World";
export default function helloWorld(){
console.log(helloTitle);
}
import helloWorld from "./hello.js"
var nickname = "AlanChen";
function test(){
console.log("Hello "+nickname);
}
// 测试
//有导出,可以访问
helloWorld();
//没有导出,无法访问
console.log(helloTitle);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./test.js" type="module"></script>
</body>
</html>
模块化导出与导入
二、组件概念
一个完整的网页是复杂的,如果将其作为一个整体来进行开发,将会遇到下面的问题:
1、代码凌乱臃肿
2、不易协作
3、难以复用
Vue推荐使用一种更加精细的控制方案:组件化开发。所谓组件化,即把一个页面中区域功能细分,每一个区域成为一个组件,每个组件包含:
1、功能(JS代码)
2、内容(模板代码)
3、样式(CSS代码)
三、组件开发
3.1 创建组件
组件是根据一个普通的配置对象创建的,所以要开发一个组件,只需要写一个配置对象即可,该配置对象和Vue实例的配置是几乎一样的。
//组件配置对象
var MyComp={
data(){
return {
// ...
}
},
computed:{
// ...
},
methods:{
// ...
},
template: `...`
}
值得注意的是,组件配置对象和Vue实例有以下几点差异:
1、无el
2、data必须是一个函数,该函数返回的对象作为数据
3、由于没有el配置,组件的虚拟DOM树必须定义在template或render中
3.2 注册组件
注册组件分为两种方式,一种是全局注册,一种是局部注册
3.2.1 全局注册
一旦全局注册了一个组件,整个应用中任何地方都可以使用该组件
全局注册全局注册的方式是:
//参数1:组件名称,将来在模板中使用组件时,会使用该名称
// 参数2:组件配置对象
// 该代码运行后,即可在模板中使用组件
Vue.component("MyComp",MyComp);
在模板中,可以使用组件了
<MyComp />
<!--或-->
<MyComp></MyComp>
但在一些工程化的大型项目中,很多组件都不需要全局使用。比如一个登录组件,只有在登录的相关页面中使用,如果全局注册,将导致构建工具无法优化打包,因此,除非组件特别通用,否则不建议使用全局注册。
3.2.2 局部注册
局部注册就是哪里要用到组件,就在哪里注册
局部注册局部注册的方式是,在要使用组件的组件或实例中加入一个配置
// vm:Vue实例
var vm = new Vue({
el:"#app", // css选择器
// 注册组件(局部注册)
components:{
Title
},
template: `<Title></Title>`,
});
3.3 应用组件
在模板中使用组件特别简单,把组件名当作html元素名使用即可。但要注意以下几点
1、组件必须有结束
组件可以自结束,也可以用结束标记结束,但必须要有结束
2、组件的命名
无论你使用哪种方式注册组件,组件的名称需要遵循规范。组件可以使用kebab-case
短横线命名法,也可以使用PascalCase
大驼峰命名法。下面两种命名均是可以的
var otherComp = {
components:{
"my-comp": myComp, //方式1
MyComp: myComp //方式2
}
}
实际上,使用小驼峰命名法,camelCase也是可以识别的,只不过不符合官方要求的规范。使用PascalCase
方式命名还有一个额外的好处,即可以在模板中使用两种组件名。
四、组件树
一个组件创建好后,往往会在各种地方使用它。它可能多次出现在Vue实例中,也可能出现在其他组件中。于是就形成了一个组件树。
组件树五、向组件传递数据
大部分组件要完成自身的功能,都需要一些额外的信息,比如一个头像组件,需要告诉它头像的地址,这就需要在使用组件时向组件传递数据。传递数据的方式有很多中,最常见的一种是使用组件属性component props
,和Vue实例一样,使用组件时也会创建组件的实例,而组件的属性会被提取到组件实例中,因此可以在模板中使用。
首先在组件中申明可以接收哪些属性
var MyComp = {
props: ["p1","p2","p3"],
template: `
<div>
{{p1}}, {{p2}}, {{p3}}
</div>
`
}
在使用组件时,向其传递属性
var OtherComp = {
componets: {
MyComp
},
data(){
return {
a:1
}
},
template: `
<my-comp :p1="a" :p2="2" p3="3"
`
}
注意:在组件中,属性是只读的,绝不可以更改,这叫单向数据流。哲学思想:谁的数据谁负责
属性不可更改六、组件创建、注册、使用、属性传值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id ="app">
</div>
<script src="./vue.min.js" ></script>
<script>
//1、组件配置对象
var Title = {
//属性
props: ["version"],
data(){
return {
title: "库存管理系统",
};
},
template: `<h1>{{title}} {{version}}</h1>`,
}
//2、注册组件(全局注册)
// Vue.component("Title",Title);
// 3、使用组件
// vm:Vue实例
var vm = new Vue({
el:"#app", // css选择器
// 2、注册组件(局部注册)
components:{
Title
},
template: `<Title version="V1.0"></Title>`,
});
</script>
</body>
</html>
七、库存管理系统 demo
库存管理系统 demo-004index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="./lib/vue.min.js"></script>
<script src="./src/main.js" type="module"></script>
</body>
</html>
main.js
import App from "./App.js";
new Vue({
components:{
App,
},
// template: `<App />`
// render(h){
// return h(App);
// }
render:(h)=>h(App),
}).$mount("#app");
App.js
import Products from "./components/Products.js";
var template = `
<div>
<h1>库存管理系统</h1>
<Products />
</div>
`;
export default{
components:{
Products
},
template,
};
Products.js
var template = `
<ul>
<li v-for="(item,i) in products">
名称:{{item.name}}
<button @click="changeStock(item,item.stock-1)">-</button>
<span v-if="item.stock>0">{{item.stock}}</span>
<span v-else>无货</span>
<button @click="changeStock(item,item.stock+1)">+</button>
<button @click="remove(i)">删除</button>
</li>
</ul>
`;
export default{
template,
data(){
return {
products:[
{id:1,name:"iphone",stock:10},
{id:2,name:"xiaomi",stock:10},
{id:3,name:"huawei",stock:10},
],
}
},
methods:{
remove(i){
this.products.splice(i,1);
},
changeStock(product,newStock){
if(newStock<0){
newStock = 0;
}
product.stock = newStock;
}
},
}
源码
源码 003、004
网友评论