vue入门
Vue概述
Vue:渐进式JavaScript框架
声明式渲染->组件系统->客户端路由->集中式状态管理->项目构建
- 易用
- 灵活
- 高效
Vue基本使用
原生js->jquery->框架
<div id="app">
{{msg}}
</div>
<script>
var vm=new Vue({
el:'#app',
data:{
msg:'Hello Vue'
}
})
</script>
el:元素的挂载位置
data:模型数据
{{}}:差值表达式
原理分析:Vue语法–(Vue框架)->原生语法
Vue模板概述
前端渲染?
把数据填充到HTML标签中
- 原生js拼接字符串(复杂,后期维护困难)
- 使用前端模板引擎(没有事件机制)
- 使用vue特有的模板语法
语法概述
-
差值表达式
-
指令(v-)
-
事件绑定
-
属性绑定
-
样式绑定
-
分支循环结构
指令
指令本质就是自定义属性
v-cloak
解决问题:闪动
原理:先隐藏,替换好值之后再显示最终的值
<style>
[v-clock] {
display: none;
}
</style>
<div v-cloak>{{msg}}</div>
v-text
相比差值表达式更加简洁,没有”闪动“问题
<div v-text="msg"></div>
msg: 'Hello Vue',
v-html
<div v-html="msg1"></div>
msg1:'<h1>Hello Vue</h1>'
比较危险,可能会导致xxs(跨站脚本危机),本网站内部数据可以使用
v-pre
<div v-pre>{{msg}}</div>
显示原始信息
数据响应式
数据变化导致页面内容的变化
- v-once只编译一次,再次更改数据不会变化,提高性能
<div v-once>{{msg}}</div>
双向数据绑定
<div>{{msg}}</div>
<label>
<input type="text" v-model="msg"/>
</label>
结果:数据同步
页面内容影响数据,数据在影响页面内容
MVVM设计思想
M(model)
V(view)
VM(View-Model)
Vue模板语法
事件绑定
v-on指令 or @
绑定函数名称
<div id="app">
<div v-cloak>{{msg}}</div>
<button v-on:click="msg++">点击</button>
<button @click="msg++">点击</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: 0
}
})
</script>
绑定函数调用
<button @click="handle(1,2,$event)">点击3</button>
<button @click="handle1">点击4</button>
var vm = new Vue({
el: '#app',
data: {
msg: 0,
},
methods:{
handle:function (p,p1,event){
console.log(event.target.innerHTML);
this.msg++;
},
handle1:function (event){
console.log(event.target.innerHTML);
}
}
})
-
如果时间直接绑定函数名称,那么默认会传递事件对象作为事件函数的第一个参数
-
如果事件绑定函数调用,那么时间对象必须作为最后一个参数显示传递,并且事件对象的名称必须是$event
事件修饰符
- 阻止冒泡
<div v-text="msg"></div>
<div v-on:click="handle1" >
<button @click="handle">按钮</button>
</div>
methods:{
handle:function (event) {
event.stopPropagation();
},
handle1:function (){
this.msg++;
}
}
或者直接使用修饰符
<button @click.stop="handle">按钮</button>
- 阻止默认行为
<button @click.prevent="handle">按钮</button>
或者直接使用修饰符
<a href="http://www.baidu.com" v-on:click.prevent>百度</a>
按键修饰符
submit:function (){
console.log(this.username+" "+this.password);
},
deleteAll:function (){
this.username='';
}
- enter回车键(示例:提交)
<input type="text" v-model="password" v-on:keyup.enter="submit">
- delete删除键(示例:删除全部)
<input type="text" v-model="username" v-on:keyup.delete="deleteAll">
Vue自定义按键修饰符
<input type="text" v-on:keyup.65="custom">
或者
<input type="text" v-on:keyup.a="custom">
Vue.config.keyCodes.a=65;
简答计算器
<div id="app">
<h1>简单计算器</h1>
数值A:<input type="text" v-model=numberA>
<br/>
数值B:<input type="text" v-model=numberB>
<br/>
<button @click="calculate">计算</button>
<br/>
计算结果:{{result}}
</div>
<script>
var v=new Vue({
el:'#app',
data:{
numberA:'',
numberB:'',
result:''
},
methods:{
calculate:function (){
this.result=parseInt(this.numberA)+parseInt(this.numberB);
}
}
})
</script>
属性绑定
<a v-bind:href="url">百度</a>
<script>
var v=new Vue({
el:'#app',
data:{
url:"http://www.baidu.com"
}
})
</script>
样式绑定
class样式处理
.active{
border: 1px solid red;
width: 100px;
height: 100px;
}
- 对象语法
<div v-bind:class="{active:isActive}"></div>
data:{
isActive:true
},methods:{
handle:function (){
this.isActive=!this.isActive;
}
}
- 数组语法
<button v-on:click="handle">按钮</button>
<div v-bind:class="[activeClass,errorClass]"></div>
data: {
activeClass: "active",
errorClass: "error"
}, methods: {
handle:function () {
this.activeClass="";
}
}
- 数组和对象结合使用
<div v-bind:class="[activeClass,errorClass,{test:isTest}]"></div>
- class绑定的值可以简化操作
<div v-bind:class="combineClass"></div>
data: {
activeClass: "active",
errorClass: "error",
combineClass:["active","error"]
}
或者
<div v-bind:class="objClass"></div>
objClass:{
active:true,
error:true
}
- 默认的class会保留
style样式处理
- 对象
<div v-bind:style="{border:borderStyle,width:widthStyle,height:heightStyle}"></div>
data: {
borderStyle:"1px solid blue",
widthStyle:"100px",
heightStyle:"100px",
}
- 数组
<div v-bind:style='[objStyles,overrideStyle]'></div>
objStyles:{
border:'1px solid green',
width:'200px',
height: '100px'
},
overrideStyle:{
backgroundColor:"red"
}
分支循环结构
<div v-if="score>=90">优秀</div>
<div v-else-if="score<90&&score>=80">良好</div>
<div v-else-if="score<80&&score>=60">及格</div>
<div v-else>不及格</div>
<div v-show="flag">测试flag</div>
- v-if和v-show的区别
v-if控制元素是否渲染到页面
v-show控制元素是否显示
循环结构
<ul>
<li v-for="(item,index) in color">{{item}}{{index}}</li>
</ul>
data: {
color:["red","blue","green","black"]
}
-
使用**:key**:帮助Vue区分不同的元素,从而提高性能
-
v-if和v-for配合使用,v-for遍历对象
<ul>
<li v-if="index==1" v-for="(value,key,index) in person">{{value}}{{key}}{{index}}</li>
</ul>
person:{
username:"张三",
password:"123",
favorite:["song","run","dance"]
}
基础案例-选项卡
<style>
*{
padding: 0;
margin: 0;
list-style: none;
}
#app{
margin: 0 auto;
}
#app ul{
overflow: hidden;
}
#app li{
display: inline-block;
float: left;
height: 20px;
width: 100px;
border: 1px solid black;
text-align: center;
}
#app .pic img{
height: 200px;
}
#app .pic div {
height: 200px;
display: none;
}
#app .pic .active{
display: block;
}
#app ul .choose{
background-color: orange;
}
</style>
<div id="app">
<div>
<ul>
<li v-for="(item,index) in picture" v-on:click="change(index)" v-bind:class='currentIndex===index?"choose":""'>{{item.name}}</li>
</ul>
<div class="pic">
<div v-for="(item,index) in picture" v-bind:class='currentIndex===index?"active":""'>
<img v-bind:src=item.path class="active">
</div>
</div>
</div>
</div>
<script>
var v = new Vue({
el: '#app',
data: {
currentIndex:0,
picture:[
{
id:0,
name:"图片01",
path:"图片01.jpg"
},
{ id:1,
name:"图片02",
path:"图片02.jpg"},
{ id:2,
name:"图片03",
path:"图片03.png"}
]
}, methods: {
change:function (index) {
this.currentIndex=index;
}
}
});
</script>
Vue常用特性
表单操作
*{
padding: 0;
margin: 0;
}
#app div span{
display: inline-block;
height: 30px;
width: 100px;
}
<div id="app">
<form action="#">
<div>
<span>姓名:</span>
<input type="text" v-model="username">
</div>
<div>
<span>性别:</span>
<input type="radio" value="1" v-model="sex" >
<label for="">男</label>
<input type="radio" value="0" v-model="sex">
<label for="">女</label>
</div>
<div>
<span>爱好:</span>
<input type="checkbox" v-model="hobbies" value="0">
<label for="">篮球</label>
<input type="checkbox" v-model="hobbies" value="1">
<label for="">唱歌</label>
<input type="checkbox" v-model="hobbies" value="2">
<label for="">写代码</label>
</div>
<div>
<span>职业:</span>
<select name="" id="" v-model="job">
<option value="0">请选择职业</option>
<option value="1">教师</option>
<option value="2">软件工程师</option>
<option value="3">律师</option>
</select>
</div>
<div>
<span>个人简历:</span>
<textarea name="" v-model="description"></textarea>
</div>
<input type="submit" v-on:click.prevent="submit">
</form>
</div>
var v = new Vue({
el: '#app',
data: {
username:'',
sex:0,
hobbies:[],
job:0,
description:''
}, methods: {
submit:function (){
console.log(this.username);
console.log(this.sex);
console.log(this.hobbies);
console.log(this.job);
console.log(this.description);
}
}
});
表单域修饰符
- 表单域转换为number类型
<textarea name="" v-model.number="description"></textarea>
- 将表单域前后空格去掉
<textarea name="" v-model.trim="description"></textarea>
- 将input事件切换为change事件
<textarea name="" v-model.lazy="description"></textarea>
自定义指令
全局指令
- 网页刷新,input获取焦点
<input type="text" v-model="username" v-focus>
Vue.directive("focus",{
inserted:function (el){
el.focus();
}
})
- 改变元素背景色
<input type="text" v-color="color">
Vue.directive("color",{
bind:function (el,binding) {
el.style.backgroundColor=binding.value;
}
})
color:"red"
局部指令
局部指令只能在组件中生效
data: {},
methods:{},
directives:{
color:{
bind:function (el,binding) {
el.style.backgroundColor=binding.value;
}
}
}
计算属性
使模板更加简洁
<div>{{reverseString}}</div>
data: {},
methods:{},
computed:{
reverseString:function (){
return this.msg.split("").reverse().join("")
}
}
- 计算属性和方法的区别
- 计算属性是基于他们的依赖进行缓存的(同一个数据则只会计算一次,结果保存在缓存中)
- 方法不存在缓存
侦听器
数据的监听
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
{{fullName}}
watch:{
firstName:function (val) {
this.fullName=val+''+this.lastName;
},
lastName:function (val) {
this.fullName=this.firstName+''+val;
}
}
登陆验证案例
- 通过v-model实现数据绑定
- 需要提供提示信息
- 需要侦听器监听输入信息的变化
- 需要修改触发的事件
<input type="text" v-model.lazy="username">
<span v-text="tip"></span>
var v = new Vue({
el: '#app',
data: {
username: '',
tip: ''
}, methods: {
checkName:function (username) {
var that=this;
setTimeout(function (){
if(username==="admin"){
that.tip="用户名不可用,请替换";
}else{
that.tip="用户名可以使用";
}
},2000);
}
},
watch: {
username: function (val) {
this.checkName(val);
this.tip = "正在验证...";
}
}
});
过滤器
格式化数据
<div>{{username|upper}}</div>
Vue.filter("upper", function (val) {
return val.charAt(0).toUpperCase()+val.slice(1);
})
和自定义指令一样,有局部过滤器
var v = new Vue({
el: '#app',
data: {
username: ''
},
methods: {},
filters: {
upper: function (val) {
return val.charAt(0).toUpperCase() + val.slice(1);
}
}
});
日期格式化
<div>{{data|format("yyyy-MM-dd hh:mm")}}</div>
data: new Date()
Vue.filter("format",function (date,fmt){
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
}
let o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
};
for (let k in o) {
if (new RegExp(`(${k})`).test(fmt)) {
let str = o[k] + '';
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));
}
}
return fmt;
function padLeftZero(str) {
return ('00' + str).substr(str.length);
}
})
声明周期
- 挂载
- 更新
- 销毁
综合案例-图书管理
<style>
* {
padding: 0;
margin: 0;
}
#booksManagement {
margin: 0 auto;
}
table {
margin: 0 auto;
border-collapse: collapse;
width: 600px;
}
table td {
border: 1px solid orange;
padding: 10px;
text-align: center;
}
table thead th {
padding: 10px;
text-align: center;
background-color: orange;
}
a {
text-decoration: none;
}
.table {
margin: 0 auto;
width: 600px;
}
.grid {
text-align: center;
margin: 25px;
}
.handle {
text-align: center;
background-color: orange;
}
.total{
padding: 10px;
text-align: center;
background-color: orange;
}
</style>
</head>
<body>
<div id="booksManagement">
<div class="table">
<div class="grid">
<h1>
图书管理
</h1>
</div>
<div class="handle">
<label>
编号:
<input type="text" v-model="id" v-bind:disabled="flag" v-focus>
</label>
<label>
名称:
<input type="text" v-model="name">
</label>
<button v-on:click="handle()" v-bind:disabled="submit">提交</button>
</div>
<div class="total">
<span >图书总数:</span>
{{total}}
</div>
</div>
<div>
<table>
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in books">
<td>{{ item.id }}</td>
<td>{{ item.bookName}}</td>
<td>{{ item.addTime}}</td>
<td><a href="#" v-on:click.prevent="editBook(item.id)">修改</a>|<a href="#" v-on:click.prevent="deleteBook(item.id)">删除</a></td>
</tr>
</tbody>
</table>
</div>
</div>
<script type="text/javascript">
Vue.filter("format", function (date, fmt) {
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
}
let o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
};
for (let k in o) {
if (new RegExp(`(${k})`).test(fmt)) {
let str = o[k] + '';
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));
}
}
return fmt;
function padLeftZero(str) {
return ('00' + str).substr(str.length);
}
});
Vue.directive("focus",{
inserted:function (el){
el.focus();
}
})
var bm = new Vue({
el: "#booksManagement",
data: {
flag: false,
id: "",
name: "",
submit:false,
books: [{
id: 1,
bookName: "三国演义",
addTime: new Date()
}, {
id: 2,
bookName: "水浒传",
addTime: new Date()
}, {
id: 3,
bookName: "红楼梦",
addTime: new Date()
}, {
id: 4,
bookName: "西游记",
addTime: new Date()
}]
},
methods: {
handle: function () {
if (this.flag) {
// 编辑操作
this.books.some((item) => {
if (item.id == this.id) {
item.bookName = this.name;
return true;
}
})
this.flag=false;
} else {
// 添加操作
var addBook = {};
addBook.id = this.id;
addBook.bookName = this.name;
addBook.date = new Date();
this.books.push(addBook);
this.id = '';
this.name = '';
}
this.id='';
this.name='';
},
editBook: function (id) {
var book = this.books.filter(function (item) {
return item.id == id;
});
this.name = book[0].bookName;
this.id = book[0].id;
this.flag = true;
},
deleteBook:function (id) {
// 删除图书
var index=this.books.findIndex(function (item){
return item.id==id;
})
this.books.splice(index,1);
}
},computed:{
total:function () {
return this.books.length;
}
},watch:{
name:function (val) {
var flag=this.books.some(function (item) {
return item.bookName==val;
});
if(flag){
this.submit=true;
}else{
this.submit=false;
}}
}
});
</script>
</body>
Vue组件化开发
组件化开发思想
- 标准
- 分治
- 重用
- 组合
组件化规范:Web Components
- 我们希望尽可能多的重用代码
- 自定义组件的方式不太容易
- 多次使用组件可能导致冲突
全局组件注册
案例
<div id="app">
<button-counter></button-counter>
</div>
// 注册组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
}, template: '<button @click="handle">点击了{{count}}次</button>',
methods:{
handle:function () {
this.count+=2;
}
}
})
var vm = new Vue({
el: "#app",
data: {}
})
注意事项
- data必须是一个函数
- 组件模板内容必须是单个根元素
- 组件模板内容可以是模板字符串
template: `<button @click="handle">点击了{{count}}次</button>`
- 组件命名方式
短横线 or 驼峰
button-counter
Buttonounter
使用驼峰式命名法,只能在字符串模板中使用组件,但是在普通的标签模板中,必须使用短横线的方式使用组件
局部组件注册
<div id="app">
<hello-world></hello-world>
<hello-tom></hello-tom>
</div>
var HelloWorld = {
data: function () {
return {
msg: 'Hello World'
}
},
template: `
<div>{{ msg }}</div>`
};
var HelloTom = {
data: function () {
return {
msg: 'Hello Tom'
}
},
template: `
<div>{{ msg }}</div>`
};
var vm = new Vue({
el: "#app",
data: {},
components: {
'hello-world': HelloWorld,
'hello-tom': HelloTom
}
});
局部组件只能在注册他的父组件中使用
组件间数据交互
父组件向子组件传值
<hello-tom title="来自父组件的值" content="来自父组件的值2"></hello-tom>
var HelloTom = {
props:['title','content'],
data: function () {
return {
msg: 'Hello Tom'
}
},
template: `
<div>{{ title+msg+content }}</div>`
};
var vm = new Vue({
el: "#app",
data: {},
components: {
'hello-tom': HelloTom
}
});
- 在props中使用驼峰形式,模板中需要使用短横线的形式
- 字符串形式的模板中没有这个限制
props属性值类型
String,Number,Boolean,数组,对象
子组件向父组件传值
子组件向父组件传值-基本用法
props传递数据原则:单项数据流
解决:
子组件通过自定义事件向父组件传递信息 $emit
父组件监听子组件的事件
<div :style="{fontSize:fontSize+'px'}">水果</div>
<menu-list :fruits="fruits" @enlarge-text="handle"></menu-list>
Vue.component('menu-list', {
props: ["fruits"],
template: `
<div>
<ul>
<li :key="index" v-for="(item,index) in fruits">{{ item }}</li>
</ul>
<button @click="fruits.push('lemon')">点击</button>
<button @click="$emit('enlarge-text')">扩大字体</button>
</div>`
})
handle: function () {
this.fontSize += 5;
}
子组件通过自定义事件向父组件传递信息
<menu-list :fruits="fruits" @enlarge-text="handle($event)"></menu-list>
<button @click="$emit('enlarge-text',5)">扩大字体</button>
<button @click="$emit('enlarge-text',10)">扩大字体</button>
单独的事件中心管理组件间的通信
通过事件中心(例:hub)管理事件的通信
<div id="app">
<test-jerry></test-jerry>
<test-tom></test-tom>
<button @click="handle">销毁事件</button>
</div>
<script type="text/javascript">
// 事件中心
var hub = new Vue();
// 注册组件
Vue.component('test-tom', {
data: function () {
return {
num: 0
}
},
template: `
<div>
<div>jerry:{{ num }}</div>
<div>
<button @click="handle">点击</button>
</div>
</div>`, methods: {
handle: function () {
hub.$emit("tom-event", 1);
}
}, mounted: function () {
hub.$on("jerry-event", (val) => {
this.num += val;
});
}
});
Vue.component('test-jerry', {
data: function () {
return {
num: 0
}
},
template: `
<div>
<div>tom:{{ num }}</div>
<div>
<button @click="handle">点击</button>
</div>
</div>`, methods: {
handle: function () {
hub.$emit("jerry-event", 2);
}
}, mounted: function () {
hub.$on("tom-event", (val) => {
this.num += val;
});
}
})
var vm = new Vue({
el: "#app",
data: {}, methods: {
handle: function () {
hub.$off("tom-event");
hub.$off("jerry-event")
}
}
});
</script>
组件插槽
<div id="app">
<alert-box>bug发生</alert-box>
<alert-box>有一个警告</alert-box>
</div>
Vue.component('alert-box', {
template: `
<div>
<strong>ERROR:</strong>
<slot></slot>
<div>`
});
具名插槽用法
<alert-box>
<h1 slot="header">header</h1>
<h1 slot="footer">footer</h1>
<h1>none</h1>
</alert-box>
Vue.component('alert-box', {
template: `
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
<div>`
});
or
<alert-box>
<template slot="header">
<h1>header</h1>
</template>
<template slot="footer">
<h1>footer</h1>
</template>
<template slot="default">
<h1>none</h1>
</template>
</alert-box>
作用域插槽
<div id="app">
<fruit-list v-bind:list="fruits">
<template slot-scope="slotProps">
<strong v-if="slotProps.info.id===2" style="color: orange">{{ slotProps.info.name }}</strong>
<span v-else>{{ slotProps.info.name }}</span>
</template>
</fruit-list>
</div>
Vue.component("fruit-list", {
props: ['list'],
template: `
<div>
<li :key="index" v-for="(item,index) in list">
<slot v-bind:info="item">{{ item.name }}</slot>
</li>
</div>
`
})
综合案例-购物车
布局,样式
* {
padding: 0;
margin: 0;
}
.container {
}
.container .cart {
width: 300px;
margin: auto;
}
.container .title {
background-color: lightblue;
height: 40px;
line-height: 40px;
text-align: center;
/*color: #fff;*/
}
.container .total {
background-color: #FFCE46;
height: 50px;
line-height: 50px;
text-align: right;
}
.container .total button {
margin: 0 10px;
background-color: #DC4C40;
height: 35px;
width: 80px;
border: 0;
}
.container .total span {
color: red;
font-weight: bold;
}
.container .item {
height: 55px;
line-height: 55px;
position: relative;
border-top: 1px solid #ADD8E6;
}
.container .item img {
width: 45px;
height: 45px;
margin: 5px;
}
.container .item .name {
position: absolute;
width: 90px;
top: 0;
left: 55px;
font-size: 16px;
}
.container .item .change {
width: 100px;
position: absolute;
top: 0;
right: 50px;
}
.container .item .change a {
font-size: 20px;
width: 30px;
text-decoration: none;
background-color: lightgray;
vertical-align: middle;
}
.container .item .change .num {
width: 40px;
height: 25px;
}
.container .item .del {
position: absolute;
top: 0;
right: 0px;
width: 40px;
text-align: center;
font-size: 40px;
cursor: pointer;
color: red;
}
.container .item .del:hover {
background-color: orange;
}
<div id="app">
<div class="container">
<my-cart></my-cart>
</div>
</div>
标题组件
var CartTitle = {
props: ["username"],
template: `
<div class="title">{{ username }}的商品</div>
`
}
列表组件
var CartList = {
props: ["list"],
template: `
<div>
<div class="item" :key="index" v-for="(item,index) in list">
<img v-bind:src="item.img"/>
<div class="name">{{ item.name }}</div>
<div class="change">
<a href="" @click.prevent="sub(item.id)">-</a>
<input type="text" class="num" v-bind:value="item.num" @blur="changeNum(item.id,$event)"/>
<a href="" @click.prevent="add(item.id)">+</a>
</div>
<div class="del" @click="del(item.id)">×</div>
</div>
</div>
`, methods: {
// 删除商品
del: function (id) {
this.$emit('cart-del', id);
},
// 数量变更
changeNum: function (id, event) {
this.$emit('change-num', {
id: id,
type: "change",
num: event.target.value
});
},
sub: function (id) {
this.$emit('change-num', {
id: id,
type: "sub"
});
},
add: function (id) {
this.$emit('change-num', {
id: id,
type: "add"
});
}
}
}
结算组件
var CartTotal = {
props: ["list"],
template: `
<div class="total">
<span>总价:{{ total }}</span>
<button>结算</button>
</div>
`, computed: {
total: function () {
// 商品总价
var total = 0;
this.list.forEach(item => {
total += item.price * item.num;
});
return total;
}
}
}
父组件
Vue.component('my-cart', {
data: function () {
return {
username: '张三',
list: [{
id: 1,
name: 'TCL彩电',
price: 1000,
num: 1,
img: 'http://img3m8.ddimg.cn/56/9/28986068-1_l_3.jpg'
}, {
id: 2,
name: '机顶盒',
price: 1000,
num: 1,
img: 'http://img3m4.ddimg.cn/72/28/28997964-1_l_1.jpg'
}, {
id: 3,
name: '海尔冰箱',
price: 1000,
num: 1,
img: 'http://img3m7.ddimg.cn/48/5/28998237-1_l_9.jpg'
}, {
id: 4,
name: '小米手机',
price: 1000,
num: 1,
img: 'http://img3m1.ddimg.cn/94/31/26193811-1_l_22.jpg'
}, {
id: 5,
name: 'PPTV电视',
price: 1000,
num: 2,
img: 'http://img3m2.ddimg.cn/88/10/29134402-1_l_3.jpg'
}]
};
},
template: `
<div class='cart'>
<cart-title v-bind:username="username"></cart-title>
<cart-list v-bind:list="list" v-on:cart-del="delCart($event)" @change-num="changeNum($event)"></cart-list>
<cart-total v-bind:list="list"></cart-total>
</div>
`,
components: {
'cart-title': CartTitle,
'cart-list': CartList,
'cart-total': CartTotal
}, methods: {
delCart: function (id) {
var index = this.list.findIndex(item => {
return item.id === id;
});
this.list.splice(id, 1);
},
changeNum: function (val) {
if(val.type==='change'){
this.list.some(item => {
if (item.id === val.id) {
item.num = val.num;
return true;
}
})
}else if(val.type==='sub'){
this.list.some(item => {
if (item.id === val.id) {
item.num -= 1;
return true;
}
})
}else if(val.type==='add'){
this.list.some(item => {
if (item.id === val.id) {
item.num += 1;
return true;
}
})
}
}
}
});
var vm = new Vue({
el: '#app',
data: {}
});