# 归档
-
《vue.js devtools安装》 - https://www.cnblogs.com/ouwen123/p/11016132.html
-
《Vue 知识点汇总(上)–附案例代码及项目地址》 - https://blog.csdn.net/wuyxinu/article/details/103965753
-
《Vue 知识点汇总(下)–附案例代码及项目地址》 - https://blog.csdn.net/wuyxinu/article/details/103966175
-
官方API - 按键修饰符 - https://cn.vuejs.org/v2/guide/events.html#按键修饰符
-
html 内置事件(去掉on即可对应vue中内置事件) - http://caibaojian.com/w3c/tags/html_ref_eventattributes.html
-
知识点(图)
文章目录
- # 归档
- # 前端渲染?
- # 渐进式?
- # 与其他JS框架的关联?
- # 特点
- # vue包含一系列的扩展插件(库):
- # Vue 初体验
- # MVVM?
- # (前面用到的)基本 options
- # Vue 的生命周期
- # 模板语法
- 官网 api - [https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4](https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4) 【指令部分】
# 前端渲染?
把数据填充HTML标签中
- js字符串拼接
(维护难) - 前端模板引擎
(方便维护、但没有专门事件机制) - vue
- 解耦视图和数据
- 可复用的组件
- 前端路由技术
- 状态管理
- 虚拟DOM
# 渐进式?
- 核心库
- 插件
- 路由
...
# 与其他JS框架的关联?
借鉴前辈的技术:
-
angular
- 模板
- 数据绑定
-
react
- 组件化
- DOM
vue 整合了以上技术
# 特点
- 遵循 MVVM 模式
- 简洁、小、效率高、支持移动、pc端
- 只关注ui、可轻松引入 vue 插件(依赖vue的) 或其他第三方库(不依赖vue的)
# vue包含一系列的扩展插件(库):
- vue-cli: vue脚手架
- vue-resource(axios): ajax请求
- vue-router: 路由
- vuex: 状态管理
- vue-lazyload: 图片懒加载
- vue-scroller: 页面滑动相关
- mint-ui: 基于vue的组件库(移动端)
- element-ui: 基于vue的组件库(PC端)
Core
+vue-router
+Vuex
# Vue 初体验
## Vue.js 安装
-
方法一:
<!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <!-- 生产环境版本,优化了尺寸和速度 --> <script src="https://cdn.jsdelivr.net/npm/vue"></script>
-
方法二:下载
开发环境 https://vuejs.org/js/vue.js
生产环境 https://vuejs.org/js/vue.min.js -
方法三:NPM
后续通过webpack和CLI的使用,我们使用该方式。
## 声明式编程
声明式编程优势:数据(data、model)和界面(view)分离
(看下面例子慢慢理解)
<body>
<div id="app">{{message}}</div>
<script src="../dist/vue.js"></script>
<script> // 编程范式:声明式编程 let mv = new Vue({ el: '#app', // 用于挂载要管理的元素 data: { // 定义数据 message: '你好啊' } }) // 元素js的做法(编程范式:命令式编程) // 1.创建div元素,设置id属性 // 2.定义一个变量叫message // 3.将message变量放在前面的div袁术中显示 </script>
</body>
## 插值: {{msg.toUpperCase()}}
、v-bind、:、v-on、@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id='app'>
<!--视图:view-->
<h2>v-model 双向数据绑定</h1>
<input type="text" v-model='username'>
<p>Hello {{username}}</p>
<h2>大括号表达式</h2>
<p>{{msg}}</p>
<p>{{msg.toUpperCase()}}</p>
<!--textContent-->
<p v-text="msg"></p>
<!--innerContent-->
<p v-html="msg"></p>
<h2>强制数据绑定</h2>
<img src="url" alt="">
<img v-bind:src="url" alt="">
<!--简写-->
<img :src="url" alt="">
<h2>绑定事件监听</h2>
<button v-on:click="test">test1</button>
<!--简写:可直接识别data参数-->
<button @click="test2(msg)">test2</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script> // 创建 vue 实例 const vm = new Vue({ // 配置对象 el: '#app', // element: 选择器 data: { // model: 数据 username: 'lawssscat', msg: `<a href="https://cn.vuejs.org/images/logo.png">logo</a>`, url: 'https://cn.vuejs.org/images/logo.png' }, methods: { test() { alert('test1'); }, test2(content) { alert(content); } }, }) </script>
</body>
</html>
## 遍历 v-for
<body>
<div id='app'>
<h2>{{message}}</h2>
<ul>
<li v-for='item in movies'>{{item}}</li>
</ul>
</div>
<script src="../dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { message: '你好啊', movies: ['海贼王', '白色相簿', '火影忍者'] } }) </script>
</body>
## 案例:计数器 - method、v-on、@
<body>
<div id='app'>
<h2>当前计数: {{counter}}</h2>
<!-- <button v-on:click="counter++">+</button> -->
<!-- <button v-on:click="counter--">-</button> -->
<button v-on:click="increment">+</button>
<button v-on:click="decrement">-</button>
</div>
<script src="../dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { counter: 0 }, methods: { increment() { this.counter++; }, decrement() { this.counter--; } }, }) // 命令式编程: // 1. 拿button元素 // 2. 添加监听事件 </script>
</body>
# MVVM?
维基:https://zh.wikipedia.org/wiki/MVVM
View层:
- 视图层
- 在我们前端开发中,通常就是DOM层。
- 主要的作用是给用户展示各种信息。
Model层:
- 数据层
- 数据可能是我们固定的死数据,更多的是来自我们服务器,从网络上请求下来的数据。
- 在我们计数器的案例中,就是后面抽取出来的obj,当然,里面的数据可能没有这么简单。
VueModel层:
- 视图模型层
- 视图模型层是View和Model沟通的桥梁。
- 一方面它实现了Data Binding,也就是数据绑定,将Model的改变实时的反应到View中
- 另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情况下改变对应的Data。
# (前面用到的)基本 options
文章目录
- # 归档
- # 前端渲染?
- # 渐进式?
- # 与其他JS框架的关联?
- # 特点
- # vue包含一系列的扩展插件(库):
- # Vue 初体验
- # MVVM?
- # (前面用到的)基本 options
- # Vue 的生命周期
- # 模板语法
- 官网 api - [https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4](https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4) 【指令部分】
# Vue 的生命周期
官网 - 生命周期 api: https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90
文章目录
- # 归档
- # 前端渲染?
- # 渐进式?
- # 与其他JS框架的关联?
- # 特点
- # vue包含一系列的扩展插件(库):
- # Vue 初体验
- # MVVM?
- # (前面用到的)基本 options
- # Vue 的生命周期
- # 模板语法
- 官网 api - [https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4](https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4) 【指令部分】
# 模板语法
官方文档 - https://cn.vuejs.org/v2/guide/syntax.html
模板语法概览
指令本质:自定义属性
指令格式:以v-开始(如:v-cloak)
## Mus`tache (胡子) - 插值表达式
- 如何将
data
中的文本数据,插入到HTML
中呢?- 已经学习过了,可以通过Mustache语法(也就是双大括号)。
Mustache: 胡子/胡须
.
- 我们可以像下面这样来使用,并且数据是响应式的
<body>
<div id='app'>
<h2>{{message}}</h2>
<!-- mustache语法中,不仅仅可以直接写变量,也可以写简单的表达式 -->
<h2>{{message}}, 主人</h2>
<h2>{{message}}, {{firstName + ' ' + lastName}}</h2>
<h2>{{counter * 2}}</h2>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { message: '你好啊', firstName: 'alan', lastName: '~~~', counter: 100 } }) </script>
</body>
## v-once 取消响应
插值表达式渲染一次后,不随变量改变
<body>
<div id='app'>
<h2>{{message}}</h2>
<h2 v-once>{{message}}</h2>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { message: '你好啊' } }) app.message = '哈哈哈' // 改了 message 值 </script>
</body>
## v-html
文本解析为html(有标签,能识别)
<body>
<div id='app'>
<h2>{{message}}</h2>
<h2 v-html="message"></h2>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { message: `<a href='http://www.baidu.com'>百度一下</a>` } }) </script>
</body>
## v-text
和 v-html 相反,文本只能识别为文本(而且会覆盖原有文本)
<body>
<div id='app'>
<h2>{{message}}</h2>
<!--不翻译标签-->
<h2 v-text="message"></h2>
<!--覆盖文本-->
<h2 v-text="message">你好骚啊</h2>
<!--覆盖文本-->
<h2 v-text="message">{{message}},你好骚啊</h2>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { message: `<a href='http://www.baidu.com'>百度一下</a>` } }) </script>
</body>
## v-pre 显示原生内容
<body>
<div id='app'>
<h2>{{message}}</h2>
<h2 v-pre="message">{{message}}</h2>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { message: `<a href='http://www.baidu.com'>百度一下</a>` } }) </script>
</body>
## v-cloak
cloak 披风、伪装
v-clock
披风,在Vue渲染前显示的样式,渲染后消失。可以用来避免未渲染文本出现
<mark>但是后面也不会用到,因为后面会用虚拟
DOM
技术</mark>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style> [v-clock] { display: none; } </style>
</head>
<body>
<!-- v-clock 披风,在Vue渲染前显示的样式,渲染后消失。可以用来避免未渲染文本出现 -->
<div id='app' v-clock>
<h2>{{message}}</h2>
</div>
<script src="./dist/vue.js"></script>
<script> setTimeout(() => { const app = new Vue({ el: '#app', data: { message: `<a href='http://www.baidu.com'>百度一下</a>` } }) }, 3000) </script>
</body>
</html>
文章目录
- # 归档
- # 前端渲染?
- # 渐进式?
- # 与其他JS框架的关联?
- # 特点
- # vue包含一系列的扩展插件(库):
- # Vue 初体验
- # MVVM?
- # (前面用到的)基本 options
- # Vue 的生命周期
- # 模板语法
- 官网 api - [https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4](https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4) 【指令部分】
## v-bind
- 某些属性我们也希望动态来绑定。
- 比如动态绑定
a
元素的href
属性 - 比如动态绑定
imgimg
元素的src
属性
- 比如动态绑定
- 这个时候,我们可以使用
v-bind
指令:- 作用:动态绑定属性
- 缩写::
- 预期:
any (with argument) | Object (without argument)
- 参数:
attrOrProp (optional)
<mark>这个用的超多</mark>
如:绑定图片 src
<body>
<div id='app'>
<img v-bind:src="url"></img>
<img :src="url"></img><!--语法糖:由于经常用到,所以有了简写-->
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { url: 'https://cn.vuejs.org/images/logo.png' } }) </script>
</body>
又如:【对象语法】 通过对象修改 class
注意:这里的
:class
不会覆盖原有的class
<h2 class='title' :class='{active: isActive,error:!isActive }'>{{message}}</h2>
如这里的
title class
仍然会保留
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style> .active { color: green; } .error { color: red; } </style>
</head>
<body>
<div id='app'>
<h2 :class='{active: isActive,error:!isActive }'>{{message}}</h2>
<button @click='change'>点击换颜色</button>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { message: '你好啊', isActive: true }, methods: { change() { this.isActive = !this.isActive; } }, }) </script>
</body>
</html>
同一个例子:只是用了访问器
<body>
<div id='app'>
<h2 :class='myClass'>{{message}}</h2>
<button @click='change'>点击换颜色</button>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { message: '你好啊', isActive: true, get myClass() { return { active: this.isActive, error: !this.isActive } } }, methods: { change() { this.isActive = !this.isActive; } }, }) </script>
</body>
又如:【数组语法】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style> .a { font-size: small; } .b { font-size: large; } .active { color: green; } .error { color: red; } </style>
</head>
<body>
<div id='app'>
<h2 :class='myClass'>{{message}}</h2>
<button @click='change'>点击换颜色</button>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { message: '你好啊', isActive: true, get myClass() { if (this.isActive) { return ['active', 'a']; } else { return ['error', 'b'] } } }, methods: { change() { this.isActive = !this.isActive; } }, }) </script>
</body>
</html>
文章目录
- # 归档
- # 前端渲染?
- # 渐进式?
- # 与其他JS框架的关联?
- # 特点
- # vue包含一系列的扩展插件(库):
- # Vue 初体验
- # MVVM?
- # (前面用到的)基本 options
- # Vue 的生命周期
- # 模板语法
- 官网 api - [https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4](https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4) 【指令部分】
## 计算属性 computed
怎么用?
<body>
<div id='app'>
<!--data-->
<h2>{{fullName}}</h2>
<!--methods-->
<!-- <h2>{{fullName()}}</h2> -->
<!--计算属性 computed-->
<h2>{{fullName}}</h2>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { firstName: 'alan', lastName: 'Wan', // get fullName() { // return `${this.firstName} ${this.lastName}`; // } }, computed: { fullName() { return `${this.firstName} ${this.lastName}`; } }, methods: { // fullName() { // return `${this.firstName} ${this.lastName}`; // } } }) </script>
</body>
必要使用
<body>
<div id='app'>
<ul>
<li v-for='book in books'>{{book.name}}:{{book.price}}</li>
</ul>
<h2>总价格:{{totalPrice}}</h2>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { books: [{ id: 11, name: 'Unix编程艺术', price: 19 }, { id: 12, name: 'Vue.js', price: 99 }, { id: 13, name: '深入理解计算机原理', price: 33 }, { id: 14, name: '现代操作系统', price: 9 }, ] }, computed: { totalPrice() { return this.books.reduce((total, book) => { return total += book.price; }, 0) } }, }) </script>
</body>
计算属性的 setter
和 getter
(访问器)
计算属性一般没有set方法,只读属性
但用了,可以实现三联
<body>
<div id='app'>
<h2>firstName: {{firstName}}</h2>
<h2>lastName: {{lastName}}</h2>
<h2>fullName: {{fullName}}</h2>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { firstName: 'AA', lastName: 'bb' }, computed: { fullName: { set(value) { const names = value.split(' '); this.firstName = names[0] || names[1] || ''; this.lastName = (names[1] && names[0]) || names[2] || ''; }, get() { return `${this.firstName} ${this.lastName}`; } } }, }) </script>
</body>
计算属性有【缓存】!!!(速度快!)
<body>
<div id='app'>
<h2>调用 computed 方法4次</h2>
<p>{{cache}}</p>
<p>{{cache}}</p>
<p>{{cache}}</p>
<p>{{cache}}</p>
<h2>调用 methods 方法4次</h2>
<p>{{nocache()}}</p>
<p>{{nocache()}}</p>
<p>{{nocache()}}</p>
<p>{{nocache()}}</p>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: {}, computed: { cache() { console.log(`调用 computed `) return 'computed'; } }, methods: { nocache() { console.log(`调用 methods `) return 'methods'; } }, }) </script>
</body>
computed
区别于 method
的核心
在官方文档中,强调了 computed
区别于 method
最重要的两点
-
<mark>
computed
是属性调用,而methods
是函数调用</mark> -
<mark>
computed
带有缓存功能,而methods
不是</mark> -
computed定义的方法我们是以属性访问的形式调用的,
{{computedTest}}
-
但是methods定义的方法,我们必须要加上()来调用,如
{{methodTest()}}
,否则,视图会出现test1的情况,见下图
-
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 text 还没有发生改变,多次访问 getText 计算属性会立即返回之前的计算结果,而不必再次执行函数。而方法只要页面中的属性发生改变就会重新执行
-
对于任何复杂逻辑,你都应当使用计算属性
-
computed依赖于data中的数据,只有在它的相关依赖数据发生改变时才会重新求值
文章目录
- # 归档
- # 前端渲染?
- # 渐进式?
- # 与其他JS框架的关联?
- # 特点
- # vue包含一系列的扩展插件(库):
- # Vue 初体验
- # MVVM?
- # (前面用到的)基本 options
- # Vue 的生命周期
- # 模板语法
- 官网 api - [https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4](https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4) 【指令部分】
## v-on、@、 事件监听
在前端开发中,我们需要经常和用于交互。
- 这个时候,我们就必须监听用户发生的时间,比如点击、拖拽、键盘事件等等
- 在Vue中如何监听事件呢?使用v-on指令
v-on 介绍 - 事件绑定
- 官方API - 按键修饰符 - https://cn.vuejs.org/v2/guide/events.html#按键修饰符
- html 内置事件(去掉on即可对应vue中内置事件) - http://caibaojian.com/w3c/tags/html_ref_eventattributes.html
- 作用:绑定事件***
- 缩写:
@
- 预期:
Function | Inline Statement | Object
- 参数:
event
(默认)|
自定义转入+$event
参数 、 event
、 $event
当通过
methods
中定义方法,以供@click
调用时,需要注意参数问题:
- 情况一:如果该方法不需要额外参数,那么方法后的()可以不添加。
但是注意:如果方法本身中有一个参数,那么会<mark>默认将原生事件event
参数传递进去</mark>- 情况二:如果需要同时传入某个参数,同时需要
event
时,可以通过$event
传入事件。
API 增强
在某些情况下,我们拿到event的目的可能是进行一些事件处理。
Vue提供了修饰符来帮助我们方便的处理一些事件:
-
.stop
- 调用event.stopPropagation()
。《JS阻止冒泡和取消默认事件(默认行为)》 - http://caibaojian.com/javascript-stoppropagation-preventdefault.html
// js 需要这样做 function stopBubble(e) { //如果提供了事件对象,则这是一个非IE浏览器 if ( e && e.stopPropagation ) //因此它支持W3C的stopPropagation()方法 e.stopPropagation(); else //否则,我们需要使用IE的方式来取消事件冒泡 window.event.cancelBubble = true; }
-
.prevent
- 调用event.preventDefault()
。《JS阻止冒泡和取消默认事件(默认行为)》 - http://caibaojian.com/javascript-stoppropagation-preventdefault.html
// js 需要这样做 //阻止浏览器的默认行为 function stopDefault( e ) { //阻止默认浏览器动作(W3C) if ( e && e.preventDefault ) e.preventDefault(); //IE中阻止函数器默认动作的方式 else window.event.returnValue = false; return false; }
-
.{keyCode | keyAlias}
- 只当事件是从特定键触发时才触发回调。 -
.native
- 监听组件根元素的原生事件。(组件时候用到) -
.once
- 只触发一次回调。
文章目录
- # 归档
- # 前端渲染?
- # 渐进式?
- # 与其他JS框架的关联?
- # 特点
- # vue包含一系列的扩展插件(库):
- # Vue 初体验
- # MVVM?
- # (前面用到的)基本 options
- # Vue 的生命周期
- # 模板语法
- 官网 api - [https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4](https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4) 【指令部分】
## 条件判断:v-if、v-else-if、v-else、及条件渲染 v-show
v-if
、v-else-if
、v-else
不建议使用,建议使用计算属性
这三个指令与JavaScript的条件语句if、else、else if类似。
Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件
简单的案例演示:
v-if
的原理:
v-if
后面的条件为 false
时,对应的元素以及其子元素不会渲染。
也就是根本没有不会有对应的标签出现在 DOM
中。
v-if 切换时候的小问题(引出概念:虚拟DOM)
<body>
<div id='app'>
<span v-if="isUser">
<label for="username">{{userText}}</label>
<input type="text" :placeholder="userText" id="username">
</span>
<span v-else>
<label for="email">{{emailText}}</label>
<input type="text" :placeholder='emailText' id="email">
</span>
<button @click='isUser=!isUser'>切换类型</button>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { userText: '用户账号', emailText: '用户邮箱', isUser: true } }) </script>
</body>
小问题:
- 如果我们在
input
输入内容的情况下,切换了类型,我们会发现文字依然显示之前的输入的内容- 为什么会这样
问题解答:
- 这是因为
Vue
在进行DOM
渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素。<mark>虚拟DOM技术(后面讲)</mark>- 在上面的案例中,
Vue
内部会发现原来的input
元素不再使用,直接作为else
中的input
来使用解决方案
- 如果我们不希望
Vue
出现类似复用的问题,可以给对应的input
添加Key
<mark>会把 key 作为一个唯一标识</mark>- 当然,要保证
Key
不同
v-show
v-show
的用法和v-if
非常相似,也用于决定一个元素是否渲染:
v-show 和 v-if 的区别
v-if
当条件为false
时,压根不会有对应的元素在DOM
中。v-show
当条件为false
时,<mark>仅仅是将元素的display
属性设置为none
而已。</mark>
<body>
<div id='app'>
<h2 v-if='isShow'>{{message}}</h2>
<h2 v-show='isShow'>{{message}}</h2>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { message: '你好啊', isShow: false } }) </script>
</body>
结论:
- 当需要在显示与隐藏之间切片很频繁时,使用v-show
- 当只有一次切换时,通过使用v-if
文章目录
- # 归档
- # 前端渲染?
- # 渐进式?
- # 与其他JS框架的关联?
- # 特点
- # vue包含一系列的扩展插件(库):
- # Vue 初体验
- # MVVM?
- # (前面用到的)基本 options
- # Vue 的生命周期
- # 模板语法
- 官网 api - [https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4](https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4) 【指令部分】
## v-for 遍历
语法
v-for
的语法类似于 JavaScript
中的 forof
循环。
- 【数组】 不要下标格式:
v-for='item in items'
或v-for='item of items'
- 【数组】要下标格式:
v-for='(item, index) in items'
其中的index就代表了取出的item在原数组的索引值。 - 【对象】不要key格式:
v-for='value in obj'
- 【对象】要key格式:
v-for='(value,key) in obj'
- 【对象】要key,要index格式:
v-for='(value,key, index) in obj'
原则:
- in 或者 of 均可(效果一样)
- 接收多个值 要用
(....)
- 有三个接收值
(value, key, index)
分别为:值、键、下标- 支持解构 (不同的是,用 of 或者 in 均可)
<li v-for='[key,value] of Object.entries(user)'>
<mark>和 JS 的 forin 、 forof 的 对比</mark>
forin
只能遍历获取key
forof
支持解构,
解构必须使用[key, value]
,分别为:键,值
不用解构 接收的是value
, 值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style> .active { color: red; } </style>
</head>
<body>
<div id='app'>
<h2>老婆们:(今晚翻牌)</h2>
<ul>
<li v-for="(m, index) in movies" :class="{active: index==activeIndex}" @click="activeChange(index)">{{m}}</li>
</ul>
</div>
<script src="./dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { movies: ['妲己', '上官婉儿', '不知火舞', '王昭君', '大乔', '小乔', '武则天'], activeIndex: 0 }, methods: { activeChange(index) { this.activeIndex = index; } }, }) </script>
</body>
</html>
【重要】 官方推荐:使用v-for时,添加:key属性
<mark>官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key属性。</mark>
为什么需要这个key属性呢(了解)?
这个其实和Vue
的 <mark>虚拟DOM</mark> 的 <mark>Diff算法</mark> 有关系。
这里我们借用React’s diff algorithm
中的一张图来简单说明一下:
当<mark>同一层</mark>有很多相同的节点时,也就是列表节点时,<mark>我们希望插入一个新的节点</mark>:
(我们希望可以在B和C之间加一个F)['a', 'b', 'c', 'd', 'e'].splice(2,0,'f')
Diff算法执行有两种情况:
.情况一:每个节点均无 Key 唯一标识(下图)
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识情况二:每个节点均有 Key 唯一标识(下图)
Diff算法就可以正确的识别此节点
找到正确的位置区插入新的节点。.
<mark>所以一句话,key的作用主要是为了高效的更新虚拟DOM。</mark>
检测数组更新 / Vue.set
<mark>因为Vue是响应式的</mark>,所以当数据发生变化时,Vue会自动检测数据变化,视图会发生对应的更新。
Vue中包含了一组观察数组编译的方法,使用它们改变数组也会触发视图的更新。
<mark>哪些组数方法 是响应式的?</mark>
- push()
- pop()
- shift() - 数组最前面<mark>删除一个</mark>元素
- unshift() - 数组最前面<mark>添加 n 个</mark>元素
- splice() - 组数在<mark>指定位置</mark>,<mark>删除指定长度</mark>并<mark>插入指定数组</mark>
JavaScript splice() 方法 - sort()
- reverse()
<mark>哪些组数方法 是响应式的?</mark>
- 直接改数组元素值:
lessons[0]='aaa';
这种情况要改成Vue.set(this.lessons, 0, 'aaa') // 或者 lessons.splice(0, 1, 'aaa')
文章目录
- # 归档
- # 前端渲染?
- # 渐进式?
- # 与其他JS框架的关联?
- # 特点
- # vue包含一系列的扩展插件(库):
- # Vue 初体验
- # MVVM?
- # (前面用到的)基本 options
- # Vue 的生命周期
- # 模板语法
- 官网 api - [https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4](https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4) 【指令部分】
## 案例:购物车
-
购物车案例 - https://blog.csdn.net/LawssssCat/article/details/104557695
-
JavaScript 浮点数陷阱及解法 - https://blog.csdn.net/LawssssCat/article/details/104555742
文章目录
- # 归档
- # 前端渲染?
- # 渐进式?
- # 与其他JS框架的关联?
- # 特点
- # vue包含一系列的扩展插件(库):
- # Vue 初体验
- # MVVM?
- # (前面用到的)基本 options
- # Vue 的生命周期
- # 模板语法
- 官网 api - [https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4](https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4) 【指令部分】
## v-model 表单绑定
## 双向绑定
<body>
<div id='app'>
<input type="text" v-model='message'>
{{message}}
</div>
<script src="../dist/vue.js"></script>
<script> const apo = new Vue({ el: '#app', data: { message: '你好啊' } }) </script>
</body>
## v-model双向绑定数组数据时遇到的天坑
前面说了,下面,直接赋值的方法不是响应式的
<mark>哪些组数方法 是响应式的?</mark>
- 直接改数组元素值:
lessons[0]='aaa';
这种情况要改成Vue.set(this.lessons, 0, 'aaa') // 或者 lessons.splice(0, 1, 'aaa')
但是 360 支持,这是为什么呢?
用Chrome浏览器
用360浏览器
查看了几个文档后发现是Chrome不兼容Object.observe
- 官网上的解释:深入响应式原理
- 博客 - vue中遇到的坑 — 变化检测问题(数组相关)
也就是说,因为360浏览器太老(没有更新)的原因,没有废弃object.server,所以才能够这样用。现阶段只能使用vue.set
解决方法
使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上。 还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名。
## (js手写)双向绑定 - ***
双向绑定原理 - https://blog.csdn.net/LawssssCat/article/details/104190288#__1279
v-model其实是一个语法糖,它的背后本质上是包含两个操作:
1.v-bind绑定一个value属性
2.v-on指令给当前元素绑定input事件
也就是说下面的代码:等同于下面的代码:
(简化版)大概如下,完整版 看源码
<body>
<div id='app'>
<input type="text" v-model='message'>
<input type="text" v-model='message'>
</div>
<script> /** * 自定义 Vue */ class Vue { constructor(config) { this.init(config); } /** * 初始化 */ init(config) { if (!(config && config.el)) throw new Error('传参数啊!') // 找el this.el = document.querySelector(config.el); // 找v-model const models = this.el.querySelectorAll(`[v-model]`); // 找data if (config.data) { // 构建***对象 this.constructorProxy(); // data赋值 for (const [property, value] of Object.entries(config.data)) { this.proxy[property] = value; } } // 添加 model 监听 models.forEach(model => { model.addEventListener('keyup', (e) => { let target = e.target; let property = target.getAttribute('v-model'); this.proxy[property] = target.value; }) }) } /** * ***对象构建 */ constructorProxy() { let handler = { get(obj, property) { return obj[property]; }, set(obj, property, value) { // 对象赋值 obj[property] = value; // v-model赋值 obj.el.querySelectorAll(`[v-model=${property}]`) .forEach(model => { model.value = value; }) // mustache赋值 // 略过... // 还有其他赋值... return true; } } this.proxy = new Proxy(this, handler); } } let mv = new Vue({ el: '#app', data: { message: '你好啊' } }) </script>
</body>
v-model 结合:radio
当存在多个单选框时
<body>
<div id='app'>
<label for="male">
<!--当存在 v-model 时, name可以去掉,也能完成互斥的效果-->
<input type="radio" id="male" name='sex' value='男' v-model='sex'>男
</label>
<label for="female">
<input type="radio" id="female" name='sex' value='女' v-model='sex'>女
</label>
<h2>您选择的性别是:{{sex}}</h2>
</div>
<script src="../dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { sex: '' } }) </script>
</body>
v-model 结合:checkbox
复选框分为两种情况:单个选框和多个选框
单选框
<body>
<div id='app'>
<label for="license">
<input type="checkbox" name="" id="license" v-model='isAgree'>同意协议
</label>
<h2>您选择的是:{{isAgree}}</h2>
<button :disabled='!isAgree' onclick="javascript:alert('ok');">下一步</button>
</div>
<script src="../dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { isAgree: false } }) </script>
</body>
多选框
<body>
<div id='app'>
<label :for="hobby+index" v-for='(hobby, index) in hobbies'>
<input type="checkbox" :value='hobby' :id='hobby+index' v-model='selectedHobbies'>{{hobby}}
</label>
<h2>您选择的是:{{selectedHobbies}}</h2>
</div>
<script src="../dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { selectedHobbies: [], hobbies: ['22娘', '33娘', '樱花庄的宠物女孩', '芽衣', '埃尔芒老师'], isAgree: false } }) </script>
</body>
v-model 结合:select
和checkbox一样,select也分单选和多选两种情况。
单选:只能选中一个值。
- v-model绑定的是一个值。
- 当我们选中option中的一个时,会将它对应的value赋值到mySelect中
单选择
<body>
<div id='app'>
<!--选择一个-->
<select name="wife" id="" v-model='selectedHobbies'>
<option :value="hobby" v-for='hobby in hobbies'>{{hobby}}</option>
</select>
<h2>您的老婆是:{{selectedHobbies}}</h2>
</div>
<script src="../dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { selectedHobbies: '', hobbies: ['22娘', '33娘', '樱花庄的宠物女孩', '芽衣', '埃尔芒老师'], isAgree: false } }) </script>
</body>
多选:可以选中多个值。
- v-model绑定的是一个数组。
- 当选中多个值时,就会将选中的option对应的value添加到数组mySelects中
多个
<body>
<div id='app'>
<!--选择一个-->
<select name="wife" id="" v-model='selectedHobbies' multiple>
<option :value="hobby" v-for='hobby in hobbies'>{{hobby}}</option>
</select>
<h2>您的老婆是:{{selectedHobbies}}</h2>
</div>
<script src="../dist/vue.js"></script>
<script> const app = new Vue({ el: '#app', data: { selectedHobbies: [], hobbies: ['22娘', '33娘', '樱花庄的宠物女孩', '芽衣', '埃尔芒老师'], isAgree: false } }) </script>
</body>
<mark>按住 ctrl 选择</mark>
v-model 的 修饰符
官网 api - https://cn.vuejs.org/v2/api/#v-model
lazy修饰符: - 懒更新
- 默认情况下,v-model默认是在input事件中同步输入框的数据的。
- 也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变。
- <mark>lazy修饰符可以让数据在失去焦点或者回车时才会更新</mark>:
number修饰符:
- 默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
- 但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
- number修饰符可以让在输入框中输入的内容自动转成数字类型:
trim修饰符:
- 如果输入的内容首尾有很多空格,通常我们希望将其去除
- trim修饰符可以过滤内容左右两边的空格