Vue是一个渐进式的框架,什么是渐进式的呢?
Vue有很多特点和Web开发中常见的高级功能
这些特点,在后面的学习和开发中都会慢慢体会到的。
学习Vuejs的前提?
NPM安装管理
创建Vue实例传入的options
el:
类型:string (#app)| HTMLElement (document.querySelector)
作用:决定之后Vue实例会管理哪一个DOM。
data:
类型:Object | Function (组件当中data必须是一个函数)
作用:Vue实例对应的数据对象。
methods:
类型:{[key:string]:Function}
作用:定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用。
(1)Hello
<body>
<div id="app">{
{message}}div>
<script src="../js/vue.js">script>
<script>
// let(变量)/ const(常量)
// 编程范式:声明式
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
message: "你好啊"
}
})
// 原生js的做法 编程范式:命令式
// 1.创建div元素,设置id属性
// 2.定义一个变量叫message
// 3.将message变量放在div元素中显示
script>
body>
(2)列表展示
<body>
<div id="app">
<ul>
<li v-for="item in movies">{
{item}}li>
ul>
div>
<script src="../js/vue.js">script>
<script>
// let(变量)/ const(常量)
// 编程范式:声明式
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
movies: ['蜘蛛侠','钢铁侠','美国队长','大话西游']
}
})
script>
body>
(3)计数器
新的属性:methods,该属性用于在Vue对象中定义方法。
新的指令:@click,该指令用于监听某个元素的点击事件,并且需要指定当发生点击时,执行的方法(方法通常是methods中定义的方法)
<body>
<div id="app">
<h2>当前计数:{
{counter}}h2>
<button @click="counter++">+button>
<button @click="counter--">-button>
div>
<script src="../js/vue.js">script>
<script>
// let(变量)/ const(常量)
// 编程范式:声明式
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
counter: 0
}
})
// 原生JS:
// 1.拿button元素
// 2.添加监听事件
script>
body>
通过methods
<body>
<div id="app">
<h2>当前计数:{
{counter}}h2>
<button @click="add">+button>
<button @click="sub">-button>
div>
<script src="../js/vue.js">script>
<script>
// let(变量)/ const(常量)
// 编程范式:声明式
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
counter: 0
},
methods: {
add: function () {
this.counter++
},
sub: function () {
this.counter--
}
}
})
script>
body>
ViewModel是Vue.js的核心,它是一个Vue实例。Vue实例是作用于某一个HTML元素上的,这个元素可以是HTML的body元素,也可以是指定了id的某个元素。
View发生点击,ViewModel监听响应,回调Model中的js函数
View层:
Model层:
ViewModel层:
当创建了ViewModel后,双向绑定是如何达成的呢?
首先,我们将上图中的DOM Listeners和Data Bindings看作两个工具,它们是实现双向绑定的关键。
从View侧看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;
从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。
<html>
<head>
<meta charset="UTF-8">
<title>title>
head>
<body>
<div id="app">
{
{ message }}
div>
body>
<script src="js/vue.js">script>
<script>
// 这是我们的Model
var exampleData = {
message: 'Hello World!'
}
// 创建一个 Vue 实例或 "ViewModel"
// 它连接 View 与 Model
new Vue({
el: '#app',
data: exampleData
})
script>
html>
在这个示例中,选项对象的el属性指向View,el: '#app’表示该Vue实例将挂载到
这个元素;data属性指向Model,data: exampleData表示我们的Model是exampleData对象。
Vue.js有多种数据绑定的语法,最基础的形式是文本插值,使用一对大括号语法,在运行时{ { message }}会被数据对象的message属性替换,所以页面上会输出"Hello World!"。
mustache语法中,不仅仅可以直接写变量,也可以写简单的表达式。
Vue.js的指令是以v-开头的,它们作用于HTML元素,指令提供了一些特殊的特性,将指令绑定在元素上时,指令会为绑定的目标元素添加一些特殊的行为,我们可以将指令看作特殊的HTML特性(attribute)。
Vue.js提供了一些常用的内置指令,接下来我们将介绍以下几个内置指令:
v-if是条件渲染指令,它根据表达式的真假来删除和插入元素,它的基本语法如下:v-if="expression"
expression是一个返回bool值的表达式,表达式可以是一个bool属性,也可以是一个返回bool的运算式。例如:
<html>
<head>
<meta charset="UTF-8">
<title>title>
head>
<body>
<div id="app">
<h1>Hello, Vue.js!h1>
<h1 v-if="yes">Yes!h1>
<h1 v-if="no">No!h1>
<h1 v-if="age >= 25">Age: {
{ age }}h1>
<h1 v-if="name.indexOf('jack') >= 0">Name: {
{ name }}h1>
div>
body>
<script src="js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
yes: true,
no: false,
age: 28,
name: 'keepfool'
}
})
script>
html>
注意:yes, no, age, name这4个变量都来源于Vue实例选项对象的data属性。
这段代码使用了4个表达式:
数据的yes属性为true,所以"Yes!"会被输出;
数据的no属性为false,所以"No!"不会被输出;
运算式age >= 25返回true,所以"Age: 28"会被输出;
运算式name.indexOf('jack') >= 0返回false,所以"Name: keepfool"不会被输出。
条件渲染小案例
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<span v-if="isUser">
<label for="username">用户账号label>
<input type="text" id="username" placeholder="用户账号" key="username">
span>
<span v-else>
<label for="email">用户邮箱label>
<input type="text" id="email" placeholder="用户邮箱" key="mail">
span>
<button @click="changeType">切换类型button>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
isUser: true
},
methods: {
changeType () {
this.isUser = !this.isUser
}
}
})
script>
body>
html>
v-show也是条件渲染指令,和v-if指令不同的是,使用v-show指令的元素始终会被渲染到HTML,它只是简单地为元素设置CSS的style属性(display)。
<body>
<div id="app">
<h1>Hello, Vue.js!h1>
<h1 v-show="yes">Yes!h1>
<h1 v-show="no">No!h1>
<h1 v-show="age >= 29">Age: {
{ age }}h1>
<h1 v-show="name.indexOf('jack') >= 0">Name: {
{ name }}h1>
div>
body>
表达式age >= 29的值为false,可以看到<h1>Age: 29h1>元素被设置了style="display:none"样式。
可以用v-else指令为v-if或v-show添加一个“else块”。v-else元素必须立即跟在v-if或v-show元素的后面——否则它不能被识别。
<html>
<head>
<meta charset="UTF-8">
<title>title>
head>
<body>
<div id="app">
<h1 v-if="age >= 25">Age: {
{ age }}h1>
<h1 v-else>Name: {
{ name }}h1>
<h1>---------------------分割线---------------------h1>
<h1 v-show="name.indexOf('keep') >= 0">Name: {
{ name }}h1>
<h1 v-else>Sex: {
{ sex }}h1>
div>
body>
<script src="js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
age: 28,
name: 'keepfool',
sex: 'Male'
}
})
script>
html>
v-else元素是否渲染在HTML中,取决于前面使用的是v-if还是v-show指令。
这段代码中v-if为true,后面的v-else不会渲染到HTML;v-show为tue,但是后面的v-else仍然渲染到HTML了。
v-for指令基于一个数组渲染一个列表,它和JavaScript的遍历语法相似:v-for="item in items"
items是一个数组,item是当前被遍历的数组元素。
v-for遍历数组和对象
<div id="app">
遍历数组
<ul>
<li v-for="item in items">{
{item}}li>
ul>
<ul>
<li v-for="(item,index) in items">{
{index}}-{
{item}}li>
ul>
遍历对象
1.在遍历对象的过程中,如果只是获取一个值,那么获取到的是value
<ul>
<li v-for="item in info">{
{item}}li>
ul>
2.获取key和value 格式:(value,key)
<ul>
<li v-for="(value,key) in info">{
{value}}-{
{key}}li>
ul>
3.获取key和value和index 格式:(value,key,index)
<ul>
<li v-for="(value,key,index) in info">{
{value}}-{
{key}}-{
{index}}li>
ul>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
items: ['why', 'kobe', 'james', 'curry'],
info: {
name: 'why',
age: 18,
height: 1.88
}
}
})
script>
遍历对象
<html>
<head>
<meta charset="UTF-8">
<title>title>
<link rel="stylesheet" href="styles/demo.css" />
head>
<body>
<div id="app">
<table>
<thead>
<tr>
<th>Nameth>
<th>Ageth>
<th>Sexth>
tr>
thead>
<tbody>
<tr v-for="person in people">
<td>{
{ person.name }}td>
<td>{
{ person.age }}td>
<td>{
{ person.sex }}td>
tr>
tbody>
table>
div>
body>
<script src="js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
people: [{
name: 'Jack',
age: 30,
sex: 'Male'
}, {
name: 'Bill',
age: 26,
sex: 'Male'
}, {
name: 'Tracy',
age: 22,
sex: 'Female'
}, {
name: 'Chris',
age: 36,
sex: 'Male'
}]
}
})
script>
html>
我们在选项对象的data属性中定义了一个people数组,然后在#app元素内使用v-for遍历people数组,输出每个person对象的姓名、年龄和性别。
v-for绑定和非绑定key的区别
组件的key属性
官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key
属性。
为什么需要这个key属性呢?(了解)
所以我们需要使用key来给每个节点做一个唯一标识(数组呢也要唯一元素,否则会报错)
key的作用主要是为了高效的更新虚拟DOM
v-bind指令可以在其名称后面带一个参数,中间放一个冒号隔开,这个参数通常是HTML元素的特性(attribute),例如:v-bind:class。
v-bind:argument="expression"
属性的动态绑定
应用:
:
v-bind的基本使用
正确的做法
<div id="app">
<img v-bind:src="imgURL">
<img :src="imgURL">
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
imgURL: 'http://5b0988e595225.cdn.sohucs.com/images/20181004/25392110ac1b425db7fe698370449cf4.jpeg'
}
})
script>
错误的做法
<img src="{
{imgURL}}">
这里不可以使用mustache语法。
v-bind绑定class 绑定方式:对象语法
v-bind绑定class(一)
以前的做法,固定变量class。
<style>
.active {
color: red;
}
style>
<div id="app">
<h2 class="active">你好啊h2>
div>
现在的做法,通过变量来决定要不要加class。
<style>
.active {
color: red;
}
style>
<div id="app">
<h2 :class="{active: isActive, line: isLine}">你好啊h2>
<button @click="btnClick">按钮button>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
isActive: 'true',
isLine: 'true'
},
methods:{
btnClick: function () {
this.isActive = !this.isActive
}
}
})
script>
v-bind绑定class(四)
<style>
.active {
color: red;
}
style>
<div id="app">
<h2 class="title" :class="getClasses">你好啊h2>
<button @click="btnClick">按钮button>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
isActive: 'true',
isLine: 'true'
},
methods:{
btnClick: function () {
this.isActive = !this.isActive
},
getClasses: function () {
return {
active: this.isActive, line: this.isLine}
},
}
})
script>
<div id="app">
<h2 class="title" :class="[active, line]">你好啊h2>
<h2 class="title" :class="getClasses()">你好啊h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
active: 'aaaaa',
line: 'bbbbb'
},
methods: {
getClasses: function () {
return {
active: this.isActive, line: this.isLine}
}
}
})
script>
vbind和vfor结合
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<style>
.active {
color: red;
}
style>
head>
<body>
<div id="app">
<li v-for="(item,index) in movies"
@click="changeColor(index)"
:class="{active: currentIndex === index}">
{
{item}}
li>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
movies: ['西游记','水浒传','红楼梦','三国演义'],
currentIndex: 0
},
methods: {
changeColor: function (index) {
this.currentIndex = index
}
}
})
script>
body>
html>
v-bind绑定style (对象语法)
:style="{key:value}"
即 :style="{属性名:属性值}"
:style="{fontSize: '25px'}"
(这种写死style就没必要绑定拉)<body>
<div id="app">
<h2 :style="{
fontSize: finalSize}">{
{message}}h2>
<h2 :style="getStyles()">{
{message}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
message: "你好啊",
finalSize: '200px'
},
methods: {
getStyles: function (){
return {
fontSize: this.finalSize}
}
}
})
script>
body>
v-bind绑定style (数组语法)
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
<h2 :style="[baseStyle]">{
{message}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
message: "你好啊",
baseStyle: {
backgroundColor: 'red'}
}
})
script>
body>
html>
v-on指令用于给监听DOM事件,它的用语法和v-bind是类似的,例如监听元素的点击事件:
有两种形式调用方法:绑定一个方法(让事件指向方法的引用),或者使用内联语句。
<div id="app">
<h2>{
{counter}}h2>
<button @click="increment">+button>
<button @click="decrement">-button>
<button v-on:click>-button>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
counter: 0
},
methods: {
increment() {
this.counter++
},
decrement() {
this.counter--
}
}
})
script>
v-on参数
$event
传入事件。<div id="app">
<h2>{
{counter}}h2>
<button @click="increment">+1button>
<button @click="Tenincrement(10, $event)">+10button>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
counter: 0
},
methods: {
increment(event) {
console.log(event);
this.counter++;
},
Tenincrement(count, event) {
console.log(event);
this.counter += 10;
}
}
})
script>
Greet按钮将它的单击事件直接绑定到greet()方法,而Hi按钮则是调用say()方法。
<html>
<head>
<meta charset="UTF-8">
<title>title>
head>
<body>
<div id="app">
<p><input type="text" v-model="message">p>
<p>
<button v-on:click="greet">Greetbutton>
p>
<p>
<button v-on:click="say('Hi')">Hibutton>
p>
div>
body>
<script src="js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello, Vue.js!'
},
// 在 `methods` 对象中定义方法
methods: {
greet: function() {
// // 方法内 `this` 指向 vm
alert(this.message)
},
say: function(msg) {
alert(msg)
}
}
})
script>
html>
v-on修饰符
.stop - 调用 event.stopPropagation()。
.prevent - 调用 event.preventDefault()。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调
1、双向绑定示例
MVVM模式本身是实现了双向绑定的,在Vue.js中可以使用v-model指令在表单元素上创建双向数据绑定。
v-model其实是一个语法糖,它的背后本质上包含两个操作
<div id="app">
<p>{
{ message }}p>
<input type="text" v-model="message"/>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
message: "Hello"
}
})
script>
将message绑定到文本框,当更改文本框的值时, { { message }}
中的内容也会被更新。
反过来,如果改变message的值,文本框的值也会被更新,我们可以在Chrome控制台进行尝试。
Vue实例的data属性指向exampleData,它是一个引用类型,改变了exampleData对象的属性,同时也会影响Vue实例的data属性。
另一种方式的双向绑定:因为v-model 相当于v-on 和v-bind:value的集合
input中value动态值绑定 —— v-bind:value
动态的给value绑定值
<label v-for="item in originHobbies" :for="item">
<input type="checkbox" :value="item" :id="item" v-model="hobbies">{
{item}}
label>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
hobbies: [], // 多选框,
originHobbies: ['篮球', '足球', '乒乓球', '羽毛球', '台球', '高尔夫球']
}
})
script>
v-model修饰符
lazy修饰符:
number修饰符:
trim修饰符:
lazy、number、trim
<div id="app">
<input type="text" v-model.lazy="message">
<h2>{
{typeof message}}-{
{message}}h2>
<input type="text" v-model.number="age">
<h2>{
{typeof age}}-{
{age}}h2>
<input type="text" v-model.trim="name">
<h2>{
{name}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
message: "你好啊",
age: 0,
name: ""
}
})
script>
2、结合radio类型
<div id="app">
<label for="male">
<input type="radio" id="male" value="男" v-model="sex">男
label>
<label for="female">
<input type="radio" id="female" value="女" v-model="sex">女
label>
<h2>您选择的性别是: {
{sex}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
sex: '女'
}
})
script>
3、结合checkbox
<div id="app">
<input type="checkbox" value="篮球" v-model="hobbies">篮球
<input type="checkbox" value="足球" v-model="hobbies">足球
<input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球
<input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
<h2>您的爱好是: {
{hobbies}}h2>
<label v-for="item in originHobbies" :for="item">
<input type="checkbox" :value="item" :id="item" v-model="hobbies">{
{item}}
label>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isAgree: false, // 单选框
hobbies: [], // 多选框,
originHobbies: ['篮球', '足球', '乒乓球', '羽毛球', '台球', '高尔夫球']
}
})
script>
4、结合select
<div id="app">
<select name="abc" v-model="fruit">
<option value="苹果">苹果option>
<option value="香蕉">香蕉option>
<option value="榴莲">榴莲option>
<option value="葡萄">葡萄option>
select>
<h2>您选择的水果是: {
{fruit}}h2>
<select name="abc" v-model="fruits" multiple>
<option value="苹果">苹果option>
<option value="香蕉">香蕉option>
<option value="榴莲">榴莲option>
<option value="葡萄">葡萄option>
select>
<h2>您选择的水果是: {
{fruits}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
fruit: '香蕉',
fruits: []
}
})
script>
v-once指令只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能
{ {message}}
如果我们直接通过{ {}}来输出,会将HTML代码也一起输出。
但是我们可能希望的是按照HTML格式进行解析,并且显示对应的内容。用法v-html=""
<div id="app">
<h2>{
{url}}h2>
<h2 v-html="url">h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
url: '百度一下'
}
})
script>
还有各种v-指令,如v-text(与{ {}}显示效果一样,但不灵活)、v-pre(直接显示,不解析)、v-cloak(在vue解析前存在,解析完后会删除,配合style的display)等等。 详情到vue官网看。
https://cn.vuejs.org/v2/api/#v-text
在某些情况,需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示
不用计算属性,也可以用methods这种方法,但是比较别扭,因为变量里没这样用方法的。
<body>
<div id="app">
<h2>{
{getFullName()}}h2>
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
firstName: 'Lebron',
lastName: 'James'
},
methods: {
getFullName() {
return this.firstName + ' ' + this.lastName
}
}
})
script>
body>
计算属性和methods的对比:
计算属性的复杂操作
对数组的价格进行相加得出总价格操作
<div id="app">
总价格:{
{totalPrice}}
div>
<script src="../js/vue.js">script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: {
// 定义数据
books: [
{
id:1,name:'aa',price:1},
{
id:2,name:'bb',price:2}
]
},
computed: {
totalPrice: function () {
let result = 0
for (let i=0; i < this.books.length; i++) {
result += this.books[i].price
}
return result
}
}
})
script>
计算属性setter和getter
理解计算属性computed的本质,代码如下。
let/var
可以将let看成更完美的var。let具有块级作用域(只有块里才能访问),var具有全局作用域和函数作用域
通俗的讲:
当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,如果返回的这个函数在外部被执行,就产生了闭包。(使函数外部能够调用函数内部定义的变量。)
介绍:主要的作用是将某个变量修饰为常量,使用const修饰的标识符为常量后,不可以再次赋值。
场景:当我们修饰的标识符不会被再次赋值时,就可以使用const来保证数据的安全性。
const的注意点
注意一:一旦给const修饰的标识符被赋值之后,不能修改
const a = 20;
a = 30; // 错误:不可以修改
注意二:使用const定义标识符,必须进行赋值
const name; // 错误:const修饰的标识符必须赋值
注意三:常量的含义是指向的对象不能修改,但是可以改变对象内部的属性
<script>
const obj = {
name: 'why',
age: 18,
height: 1.88
}
obj.name = 'kobe';
obj.age= 40;
obj.height = 1.87;
console.log(obj)
</script>
因为Vue是响应式的,所以当数据发生变化时,Vue会自动检测数据变化,视图会发生对应的更新。
Vue中包含了一组观察数组编译的方法,使用它们改变数组也会触发视图的更新。
如通过索引值修改数组中的元素,这个是没有响应式的。
this.letters[0] = 'bbbbb';
补充个之前遗忘的HTML知识
<div id="app">
<span>
<label for="username">用户账号label>
<input type="text" id="username">
span>
div>
index.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<link rel="stylesheet" href="style.css">
head>
<body>
<div id="app">
<div v-if="books.length">
<table>
<thead>
<tr>
<th>th>
<th>书籍名称th>
<th>出版日期th>
<th>价格th>
<th>购买数量th>
<th>操作th>
tr>
thead>
<tbody>
<tr v-for="(item,index) in books">
<td>{
{item.id}}td>
<td>{
{item.name}}td>
<td>{
{item.date}}td>
<td>{
{item.price | showPrice}}td>
<td>
<button @click="decrement(index)" v-bind:disabled="item.count <= 1">-button>
{
{item.count}}
<button @click="increment(index)">+button>
td>
<td><button @click="removeHandle(index)">移除button>td>
tr>
tbody>
table>
<h2>总价格:{
{totalPrice | showPrice}}h2>
div>
<h2 v-else>购物车为空h2>
div>
<script src="../js/vue.js">script>
<script src="main.js">script>
body>
html>
main.js
const app = new Vue({
el: '#app',
data: {
books: [
{
id: 1,
name: '算法导论',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 1,
name: '算法导论',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 2,
name: '算法导论',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 3,
name: '算法导论',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 4,
name: '算法导论',
date: '2006-9',
price: 85.00,
count: 1
}
]
},
methods: {
// getFinalPrice(price) {
// return '¥' + price.toFixed(2)
// },
increment(index) {
this.books[index].count++
},
decrement(index) {
this.books[index].count--
},
removeHandle(index) {
this.books.splice(index,1)
}
},
computed: {
totalPrice() {
// 1.普通的for循环
// let totalPrice = 0
// for (let i = 0; i < this.books.length; i++) {
// totalPrice += this.books[i].price * this.books[i].count
// }
// return totalPrice
// 2.for (let i in this.books)
// let totalPrice = 0
// for (let i in this.books) {
// const book = this.books[i]
// totalPrice += book.price * book.count
// }
//
// return totalPrice
// 3.for (let i of this.books)
// let totalPrice = 0
// for (let item of this.books) {
// totalPrice += item.price * item.count
// }
// return totalPrice
return this.books.reduce(function (preValue, book) {
return preValue + book.price * book.count
}, 0)
}
},
filters: {
showPrice(price) {
return '¥' + price.toFixed(2)
}
}
})
css
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
}
th, td {
padding: 8px 16px;
border: 1px solid #e9e9e9;
text-align: left;
}
th {
background-color: #f7f7f7;
color: #5c6b77;
font-weight: 600;
}
filter/map/reduce
// 编程范式: 命令式编程/声明式编程
// 编程范式: 面向对象编程(第一公民:对象)/函数式编程(第一公民:函数)
// filter/map/reduce
// filter中的回调函数有一个要求: 必须返回一个boolean值
// true: 当返回true时, 函数内部会自动将这次回调的n加入到新的数组中。 最后新的数组会作为返回值
// false: 当返回false时, 函数内部会过滤掉这次的n
const nums = [10, 20, 111, 222, 444, 40, 50]
// let total = nums.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n);
// console.log(total);
let total = nums.filter(function (n) {
return n < 100
}).map(function (n) {
return n * 2
}).reduce(function (prevValue, n) {
return prevValue + n
}, 0)
console.log(total);
// 1.filter函数的使用
// // 10, 20, 40, 50
// let newNums = nums.filter(function (n) {
// return n < 100
// })
// // console.log(newNums);
//
// // 2.map函数的使用
// // 20, 40, 80, 100
// let new2Nums = newNums.map(function (n) { // 20
// return n * 2
// })
// console.log(new2Nums);
//
// // 3.reduce函数的使用
// // reduce作用对数组中所有的内容进行汇总
// // preValue是上一个的返回值。在这里等同于 preValue = preValue + n
// let total = new2Nums.reduce(function (preValue, n) {
// return preValue + n
// }, 0)
// console.log(total);
// 第一次: preValue=0 n=20
// 第二次: preValue 20 n 40
// 第二次: preValue 60 n 80
// 第二次: preValue 140 n 100
// 240
// // 1.需求: 取出所有小于100的数字
// let newNums = []
// for (let n of nums) {
// if (n < 100) {
// newNums.push(n)
// }
// }
//
// // 2.需求:将所有小于100的数字进行转化: 全部*2
// let new2Nums = []
// for (let n of newNums) {
// new2Nums.push(n * 2)
// }
//
// console.log(new2Nums);
//
//
// // 3.需求:将所有new2Nums数字相加,得到最终的结果
// let total = 0
// for (let n of new2Nums) {
// total += n
// }
//
// console.log(total);