参考资料
练习题 icon lost
交流讨论
我的笔记
专栏课程

一、邂逅Vue.js

1、认识Vue.js

Vue是一个渐进式的框架,什么是渐进式的呢?

  • 渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验。
  • 或者如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统。
  • 比如Core+Vue-router+Vuex,也可以满足你各种各样的需求。

Vue有很多特点和Web开发中常见的高级功能

  • 解耦视图和数据
  • 可复用的组件- 前端路由技术
  • 状态管理
  • 虚拟DOM

这些特点,在后面的学习和开发中都会慢慢体会到的。

学习Vuejs的前提?

  • 从零学习Vue开发,并不需要你具备其他类似于Angular、React,甚至是jQuery的经验。
  • 但是你需要具备一定的HTML、CSS、JavaScript基础。

2、Vue.js安装方式

CDN引入
在这里插入图片描述

下载和引入
在这里插入图片描述

NPM安装管理

  • 通过webpack和CLI的使用

3、Vue初体验

创建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>
  <!-- v-on:click = @click -->
  <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>
  <!-- v-on:click = @click -->
  <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>

4、Vue的MVVM框架

在这里插入图片描述
ViewModel是Vue.js的核心,它是一个Vue实例。Vue实例是作用于某一个HTML元素上的,这个元素可以是HTML的body元素,也可以是指定了id的某个元素。

View发生点击,ViewModel监听响应,回调Model中的js函数
View层:

  • 视图层
  • 在我们前端开发中,通常就是DOM层。
  • 主要的作用是给用户展示各种信息。

Model层:

  • 数据层
  • 数据可能是我们固定的死数据,更多的是来自我们服务器,从网络上请求下来的数据。
  • 在我们数器的案例中,就是后面抽取出来的obj,当然,里面的数据可能没有这么简单。

ViewModel层:

  • 视图模型层
  • 视图模型层是View和Model沟通的桥梁。
  • 一方面它实现了Data Binding,也就是数据绑定,将Model的改变实时的反应到View中
  • 另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情况下改变对应的Data。

在这里插入图片描述

当创建了ViewModel后,双向绑定是如何达成的呢?
首先,我们将上图中的DOM Listeners和Data Bindings看作两个工具,它们是实现双向绑定的关键。
从View侧看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;
从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>

	<body>
		<!--这是我们的View-->
		<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>
  1. 定义View
  2. 定义Model
  3. 创建一个Vue实例或"ViewModel",它用于连接View和Model
    在创建Vue实例时,需要传入一个选项对象,选项对象可以包含数据、挂载元素、方法、模生命周期钩子等等。

在这个示例中,选项对象的el属性指向View,el: '#app’表示该Vue实例将挂载到<div id="app">...</div>这个元素;data属性指向Model,data: exampleData表示我们的Model是exampleData对象。
Vue.js有多种数据绑定的语法,最基础的形式是文本插值,使用一对大括号语法,在运行时{{ message }}会被数据对象的message属性替换,所以页面上会输出"Hello World!"。

模板template
在这里插入图片描述

二、Vue基础语法

mustache语法中,不仅仅可以直接写变量,也可以写简单的表达式。

Vue.js的指令是以v-开头的,它们作用于HTML元素,指令提供了一些特殊的特性,将指令绑定在元素上时,指令会为绑定的目标元素添加一些特殊的行为,我们可以将指令看作特殊的HTML特性(attribute)。

Vue.js提供了一些常用的内置指令,接下来我们将介绍以下几个内置指令:

  • v-if指令
  • v-show指令
  • v-else指令
  • v-for指令
  • v-bind指令
  • v-on指令
  • v-once指令

v-if指令

v-if是条件渲染指令,它根据表达式的真假来删除和插入元素,它的基本语法如下:v-if="expression"
expression是一个返回bool值的表达式,表达式可以是一个bool属性,也可以是一个返回bool的运算式。例如:

<!DOCTYPE html>
<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"不会被输出。

条件渲染小案例

  • 用户登录时,可以切换使用用户账号登录还是邮箱地址登录
  • 切换时,input框要清空(如果缺少key的话,会导致切换时,输入框扔保存上一个类型的值) —— 先把要渲染的东西通过虚拟DOM放到内存里
  • 如果我们在有输入内容的情况下,切换了类型,我们会发现文字依然显示之前的输入的内容。这是因为Vue进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素。
  • 解决方案:如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key,并且我们需要保证key的不同。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</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-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: 29</h1>元素被设置了style="display:none"样式。

v-else指令

可以用v-else指令为v-if或v-show添加一个“else块”。v-else元素必须立即跟在v-if或v-show元素的后面——否则它不能被识别。

<!DOCTYPE html>
<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指令

v-for指令基于一个数组渲染一个列表,它和JavaScript的遍历语法相似:v-for="item in items"
items是一个数组,item是当前被遍历的数组元素。

v-for遍历数组和对象

<div id="app">
    遍历数组
<!--    1.在遍历的过程中,没有使用索引值-->
    <ul>
      <li v-for="item in items">{{item}}</li>
    </ul>

<!--    2.在遍历的过程中,获取索引值-->
    <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>

遍历对象

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
		<link rel="stylesheet" href="styles/demo.css" />
	</head>

	<body>
		<div id="app">
			<table>
				<thead>
					<tr>
						<th>Name</th>
						<th>Age</th>
						<th>Sex</th>
					</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属性呢?(了解)

  • 这个其实和Vue的虚拟DOM的Diff算法,对比有无变化。创建新的元素并插入位置,导致后面的也跟随更新。
    在这里插入图片描述
  • 当某一层有很多相同的节点,也就是列表节点时,我们希望插入一个新的节点。(如下步骤,过于繁琐,效率低)
    • 我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的。
    • 即把C更新成F,D更新成C,E更新成D,最后再插入E。

所以我们需要使用key来给每个节点做一个唯一标识(数组呢也要唯一元素,否则会报错)

  • Diff算法就可以正确的识别此节点
  • 找到正确的位置区插入新的节点
    在这里插入图片描述

key的作用主要是为了高效的更新虚拟DOM

v-bind指令

v-bind指令可以在其名称后面带一个参数,中间放一个冒号隔开,这个参数通常是HTML元素的特性(attribute),例如:v-bind:class。
v-bind:argument="expression" 属性的动态绑定
应用:

  • 动态绑定a元素的href属性
  • 动态绑定img元素的src属性
  • 语法糖::

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 绑定方式:对象语法

  • 对象语法的含义是:class后面跟的是一个对象
  • 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>

v-bind绑定class 绑定方式:数组语法
在这里插入图片描述

<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结合

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <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="{属性名:属性值}"
  • 示例1::style="{fontSize: '25px'}"(这种写死style就没必要绑定拉)
    本质上是不用加单引号的,但在vue里面,不加的话会被当成变量,去寻找data下的变量。还有这里采用驼峰式格式fontSize
  • 示例2:
    <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 (数组语法)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</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指令

v-on指令用于给监听DOM事件,它的用语法和v-bind是类似的,例如监听<a>元素的点击事件:<a v-on:click="doSomething">
有两种形式调用方法:绑定一个方法(让事件指向方法的引用),或者使用内联语句。

<div id="app">
    <h2>{{counter}}</h2>
<!--    <button v-on:click="counter++">+</button>-->
<!--    <button v-on:click="counter&#45;&#45;">-</button>-->
    <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参数传递进去。
  • 情况二:如果该方法需要传入某个参数,同时需要event时,可以通过$event传入事件。
<div id="app">
    <h2>{{counter}}</h2>
    <button @click="increment">+1</button>
    <button @click="Tenincrement(10, $event)">+10</button>
</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()方法。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<p><input type="text" v-model="message"></p>
			<p>
				<!--click事件直接绑定一个方法-->
				<button v-on:click="greet">Greet</button>
			</p>
			<p>
				<!--click事件使用内联语句-->
				<button v-on:click="say('Hi')">Hi</button>
			</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 - 只触发一次回调

在这里插入图片描述

v-model ❤

1、双向绑定示例

MVVM模式本身是实现了双向绑定的,在Vue.js中可以使用v-model指令在表单元素上创建双向数据绑定。

v-model其实是一个语法糖,它的背后本质上包含两个操作

  • v-bind绑定一个value属性
  • v-on指令给当前元素绑定input事件
<!--这是我们的View-->
<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绑定到文本框,当更改文本框的值时,<p>{{ message }}</p> 中的内容也会被更新。
在这里插入图片描述
反过来,如果改变message的值,文本框的值也会被更新,我们可以在Chrome控制台进行尝试。
在这里插入图片描述

Vue实例的data属性指向exampleData,它是一个引用类型,改变了exampleData对象的属性,同时也会影响Vue实例的data属性。

另一种方式的双向绑定:因为v-model 相当于v-on 和v-bind:value的集合
<input type="text" :value="message" @input="message"="$event.target.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修饰符:

  • 默认情况下,V-mode默认是在input事件中同步输入框的数据的。
  • 也就是说,一旦有数据发生改变对应的data的数据就会自动发生改变。
  • lazy修饰符可以让数据在失去焦点或者回车时才会更新:

number修饰符:

  • 默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
  • 但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
  • number修饰符可以让在输入框中输入数字的内容自动转成数字类型:

trim修饰符:

  • 如果输入的内容首尾有很多空格,通常我们希望将其去除口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">
  <!--1.checkbox单选框-->
<!--  <label for="agree">-->
<!--    <input type="checkbox" id="agree" v-model="isAgree">同意协议-->
<!--  </label>-->
<!--  <h2>您选择的是: {{isAgree}}</h2>-->
<!--  <button :disabled="!isAgree">下一步</button>-->

  <!--2.checkbox多选框-->
  <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">
  <!--1.选择一个-->
  <select name="abc" v-model="fruit">
    <option value="苹果">苹果</option>
    <option value="香蕉">香蕉</option>
    <option value="榴莲">榴莲</option>
    <option value="葡萄">葡萄</option>
  </select>
  <h2>您选择的水果是: {{fruit}}</h2>

  <!--2.选择多个-->
  <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指令

v-once指令只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能
<h2 v-once>{{message}}</h2>

v-html指令

如果我们直接通过{{}}来输出,会将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: '<a href="http://www.baidu.com">百度一下</a>'
    }
  })
</script>

在这里插入图片描述

还有各种v-指令,如v-text(与{{}}显示效果一样,但不灵活)、v-pre(直接显示,不解析)、v-cloak(在vue解析前存在,解析完后会删除,配合style的display)等等。 详情到vue官网看。
https://cn.vuejs.org/v2/api/#v-text

计算属性

在某些情况,需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示

  • 比如我们有firstName和lastName两个边路,我们需要显示完整的名称。
  • 但是如果多个地方都需要显示完整的名称,我们就需要写多个{{firstName}} {{lastName}}
    在这里插入图片描述

不用计算属性,也可以用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的对比:

  • 计算属性比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的本质,代码如下。

  • 在某些情况下,可以提供一个setter方法(不常用)。 getter方法是默认调用,按照上例那种可以不写
  • 在需要写setter的时候,代码如下

ES6补充

块级作用域let

let/var
可以将let看成更完美的var。let具有块级作用域(只有块里才能访问),var具有全局作用域和函数作用域
在这里插入图片描述

通俗的讲:

  • var相当于共享,let是块级作用域有自己的i。
  • ES5之前因为if和for都没有块级作用域的概念,所以在很多时候,我们都必须借助于function的作用域来解决应用外面变量的问题(通过函数形参,闭包函数,如图左侧示例)。

当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,如果返回的这个函数在外部被执行,就产生了闭包。(使函数外部能够调用函数内部定义的变量。)
在这里插入图片描述

const的使用

介绍:主要的作用是将某个变量修饰为常量,使用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>

对象增强写法

在ES6,属性初始化简写和方法的简写
在这里插入图片描述

数组哪些方法是响应式

因为Vue是响应式的,所以当数据发生变化时,Vue会自动检测数据变化,视图会发生对应的更新。

Vue中包含了一组观察数组编译的方法,使用它们改变数组也会触发视图的更新。

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

如通过索引值修改数组中的元素,这个是没有响应式的。

this.letters[0] = 'bbbbb';

补充个之前遗忘的HTML知识

  • 通过label for绑定input,做到点击label就可以输入
    <div id="app">
        <span>
            <label for="username">用户账号</label>
            <input type="text" id="username">
        </span>
    </div>
    

购物车案例

在这里插入图片描述

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <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>{{getFinalPrice(item.price)}}</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;
}

Java高阶函数

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);
资料来源 Vue知识(一)Vue基础语法
博客作者 果子哥丶
前往答题
发布见解