一、使用Webpack以及Babel打包的组件
1.1 vue-cli介绍
vue-cli是一个基于Vue.js进行快速开发的完整系统。它主要提供了以下功能:
- 通过@vue/cli搭建交互式的项目脚手架;
- 继承Webpack,并做了默认配置,简化vue组件的开发模式;
- 提供了多种vue开发环境依赖(如构建工具、内置服务器);
- 为用户提供了多种vue的插件包;
在使用vue-cli工具构建的项目中,每一个独立的vue文件都在打包阶段封装成一个局部组件。vue文件的典型结构如下:
<template>
</template>
<script>
export default {
}
</script>
<style>
</style>
template:模版区域,封装局部组件的html代码,显示组件内容;
style:模版样式区域,封装局部组件所使用的样式;
script:模版的对象区域,声明data、methods等组件的属性;
在父组件中引入子组件:
1)使用import命令;
2)在components中声明使用该组件;
<script>
// 1. 引入Cart组件
import Cart from './components/Cart.vue'
export default {
name: 'app',
components: {
Cart // 2. 加载购物车组件
}
}
</script>
1.2 vue-cli安装
考虑到安装速度,建议使用cnpm安装vue脚手架。
第一步:安装cnpm;
npm install cnpm-registry=https://registry.npm.taobao.org -g
第二步:安装vue-cli;
cnpm install @vue/cli -g
安装成功后,输入命令vue --version查看版本信息。
1.3 vue-cli单文件配置
对单个js文件或vue文件启动启动一个web服务器。
实现步骤:
第一步:安装vue-server;
npm install @vue/cli-service-global -g
第二步:新建Hello.vue文件,内容如下:
<template>
<h1>Hello World</h1>
</template>
第三步:在文件所在目录下执行命令启动服务器;
vue serve Hello.vue
启动成功后界面:
如果要生成最终的html与js文件,可以执行下面命令:
vue build Hello.vue
1.4 vue项目构建
第一步:在vue工作空间中使用vue指令创建项目;
vue create 项目名
第二步:选择默认配置;
项目构建完成后的目录结构如下所示:
public:存放静态资源;
src:存放源码;
babel.config.js:babel配置
README.md:项目文档
第三步:启动服务。
npm run serve
二、购物车案例
2.1 商品列表展示
<template>
<div id="app">
<ul>
<li v-for='(good, i) in goods' :key='good.text'>
<span>{{good.text}}</span>
<span>¥{{good.price}}</span>
<button @click='addCart(i)'>添加购物车</button>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'app',
components: {
},
data() {
return {
goods: [
{text: 'Java基础入门', price: 99},
{text: 'Oracle数据库', price: 69},
{text: '分布式项目实战', price: 89},
{text: '前端开发', price: 109}
]
}
},
methods: {
addCart(i) {
// TODO 添加购物车代码实现
}
}
}
</script>
<style>
</style>
2.2 购物车组件
在src/templates目录下新建Cart.vue文件。
<template>
<div>
<div>
{{name}}的购物车:
</div>
<table border="1">
<tr>
<th>操作</th>
<th>课程名</th>
<th>单价</th>
<th>数量</th>
<th>价格</th>
</tr>
<tr v-for="(cart, i) in carts" :key="cart.text">
<td>{{cart.text}}</td>
<td>{{cart.price}}</td>
<td>{{cart.count}}</td>
<td>{{cart.count * cart.price}}</td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: 'Cart',
props: {
name : {
type: String,
required: true
},
carts: {
type: Array
},
},
data() {
return {
}
}
}
</script>
<style>
</style>
上面Cart组件中定义了两个属性:name和carts。而且name属性是必须的。
2.3 使用组件
第一步:修改App.vue,引入Cart.vue文件;
import Cart from './components/Cart.vue'
第二步:加载Cart组件;
export default {
name: 'app',
components: {
Cart // 加载购物车组件
},
...
}
第三步:在template中使用Cart组件;
<Cart :name="name" :carts="carts"></Cart>
第四步:绑定name和carts变量;
data() {
return {
goods: [
{text: 'Java基础入门', price: 99},
{text: 'Oracle数据库', price: 69},
{text: '分布式项目实战', price: 89},
{text: '前端开发', price: 109}
]
name: 'joe',
carts: [],
}
},
2.4 添加购物车
第一步:定义addCart函数;
methods: {
// 添加购物车,通过消息总线把要添加购物车的商品传递给Cart组件
addCart(i) {
// 获取要添加购物车的商品
const good = this.goods[i]
// 触发addCart事件,该事件在Cart组件中定义
this.$bus.$emit('addCart', good)
}
}
上面addCart函数中获取添加购物车的商品,然后向子组件发送addCart事件,并把商品传递到子组件中;
第二步:在子组件的created函数中监听addCart事件;
created() {
// 定义事件监听器,监听addCart事件
this.$bus.$on('addCart', good => {
// 找出购物车商品
const ret = this.carts.find(v => v.text == good.text)
// 判断商品是否存在
// 如果存在,则修改购物车商品的数量
// 如果不存在,则把商品添加到购物车中
if (ret) {
ret.count += 1
} else {
this.carts.push({...good, active: true, count: 1})
}
})
},
2.5 购物车商品数量修改
第一步:在Cart组件中添加“加减”按钮;
<td>
<button @click="minus(i)">-</button>
{{cart.count}}
<button @click="add(i)">+</button>
</td>
第二步:实现minus和add函数;
methods: {
// 购物车商品数量减1
minus(i) {
const count = this.carts[i].count
if (count > 1) {
this.carts[i].count -= 1
} else {
this.remove(i)
}
},
// 购物车商品数量加1
add(i) {
this.carts[i].count += 1
},
// 删除购物车商品
remove(i) {
if (window.confirm(`是否删除商品${this.carts[i].text}?`)) {
this.carts.splice(i, 1)
}
}
}
2.6 绑定class样式
设置单选框,根据选中状态修改购物商品文字颜色。
第一步:在Cart组件中增加复选框;
<tr v-for="(cart, i) in carts" :key="cart.name">
<td>
<input type="checkbox" v-model="cart.active">
</td>
....
</tr>
第二步:class绑定;
<tr v-for="(cart, i) in carts" :key="cart.name" :class="{active:cart.active}">
第三步:定义class样式;
<style>
.active {
color: green;
}
</style>
2.7 计算属性
第一步:在购物车列表最后增加统计行;
<tr>
<td></td>
<td colspan="2">{{activeCount}}/{{count}}</td>
<td colspan="2">¥{{total}}</td>
</tr>
第二步:在computed函数中实现统计业务逻辑;
// 定义计算函数,但组件属性name或carts发生变化的时候,自动执行computed中的所有函数
computed: {
// 购物车数量
count() {
return this.carts.length
},
// 购物车选中商品数量
activeCount() {
return this.carts.filter(v => v.active).length
},
// 总金额
total() {
let num = 0
this.carts.forEach(v => {
if (v.active) {
num += v.price * v.count
}
})
return num
}
},
2.8 mock商品数据
使用自带的webpack-dev-server来模拟请求商品数据。
第一步:在项目根路径下新建vue.config.js文件,文件内容如下:
module.exports = {
// 扩展Webpack配置
configureWebpack: {
// 配置开发服务器
devServer: {
// 配置前置中间件,参数app相当于获取当前正在启动的服务器
before(app) {
// mock数据,用于接口测试
// 需要先安装axios(命令:npm i axios -S)
app.get('/api/goods', function(req, resp) {
// 后台返回json数据
resp.json({
list: [
{text: '百万年薪不是梦', price: 100},
{text: 'Web全栈工程师', price: 120},
{text: 'Python爬虫', price: 80},
]
})
})
}
}
}
}
第二步:启动服务器,并访问localhost:8080/api/goods,可以看到响应数据;
第三步:安装axios;
npm install axios
第四步:在父组件的created函数中请求数据;
created() {
// 查询产品列表
axios.get('/api/goods').then(res => {
this.goods = res.data.list
})
},
2.9 数据持久化
使用localstorage+vue监听器实现数据持久化。
第一步:在watch对象中观察carts状态变化,如果carts状态发生变化,则把carts对象转换成json字符串,然后再保存在localStorage中;
// 观察carts属性状态的变化
watch: {
carts: {
handler(n) {
localStorage.setItem("carts", JSON.stringify(n))
},
deep: true
}
},
上面指定deep=true,代表启动深层观察,即观察数组元素状态的变化。
第二步:在data函数中,从localStorage中读取carts数据,并转换成json对象后赋值给carts变量。
data() {
return {
carts: JSON.parse(localStorage.getItem("carts")) || []
}
},