VueVue 3.0 笔记
WaterBoatNode(后端)中的 MVC 与 前端中的 MVVM 之间的区别(了解内容)
- MVC 主要是后端的分层开发思想;把 一个完整的后端项目,分成了三个部分:
- Model:(数据层)主要负责 数据库的操作;
- View:(视图层)所有前端页面,统称为 View 层
- Controller:(业务逻辑层)主要处理对应的业务逻辑;(对于后台来说,这是开发的重点)
- MVVM 是前端页面的分层开发思想,主要关注于 视图层 分离,也就是说:MVVM 把前端的视图层,分为了 三部分 Model, View, ViewModel
- Model 是 页面中,需要用到的数据
- View 是页面中的 HTML 结构;
- ViewModel 是 一个 中间的调度者,提供了双向数据绑定的概念;
- 为什么有了 MVC 还要有 MVVM
- 因为 MVC 是后端的开发思想,并没有明确定义前端的页面该如何开发;
- MVVM 是前端的页面的开发思想,把每个页面,分成了三个部分,同时 VM 作为 MVVM 的核心,提供了双向数据绑定的概念,前端程序员,不需要手动渲染页面了,而且,页面数据发送变化,也不需要程序员手动把 数据的变化同步到 Model 中;这所有的操作,都是 VM 自动完成的!
- 有了 MVVM 的思想以后,前端只关心 页面交互逻辑,不关心页面如何渲染;
Vue.js 基本代码 和 MVVM 之间的对应关系
- 注意:Vue 中,不推荐程序员手动操作 DOM 元素;所以,在 Vue 项目中,没有极其变态的需求,一般不要引入 Jquery;
- Vue 代码解析执行的步骤:
- 当 VM 实例对象,被 创建完成之后 把模板和数据进行绑定 存储到内存中;
- 当 VM 调用 mount()方法的时候 ,看到 mount(元素)把内存中已经渲染好的 html 结构插入到元素中去
- 注意:每当 vm 实例对象,监听到 data 中数据发生了变化,就会立即 重新解析 重新指向 model 内,所有的代码;
什么是 Vue 中的指令
定义: Vue 中,通过一些特殊的语法,扩展了 HTML 的能力;
- 将来 创建 Vue 实例的时候,Vue 会把 这些指令 都进行解析,从而,根据不同的指令,执行不同的操作、渲染不同的结果;
8.1 Vue 指令之 插值表达式 {\{ }\}
基本使用演示
在指定的位置动态插入内容,例如:
在插值表达式中 使用简单的语句
注意:插值表达式只能用在元素的内容区域;不能用在元素的属性节点中;
8.2 Vue 指令之 v-cloak
- 解决的问题
- 插值表达式有闪烁的问题(
v-cloak
指令来解决闪烁问题)
- 应用场景
- 当 网络比较卡的时候,我们可以为 最外层的 元素,添加
v-cloak
,防止用户看到 插值表达式
8.3 Vue 指令之 v-text
基本使用
在 元素的属性节点上,添加v-text
指令,例如:
在v-text
中 使用简单的语句
v-text
与 {{}}
的区别
应用场景
8.4 Vue 指令之 v-html
基本使用
在 元素的属性节点上,添加v-html
指令,例如:
1
| <div v-html="msg"></div>
|
应用场景
当 服务器返回的数据中,包含的 HTML 的标签,此时,这些标签只能使用 v-html
来渲染;
8.5 Vue 指令之 v-bind:
属性绑定
基本使用
应用场景
- 如果元素的属性值,需要动态地进行绑定,则需要使用
v-bind:
指令
简写形式
8.6 Vue 指令之 v-on:
事件绑定
基本使用:
v-on:
的作用,是为 HTML 元素,绑定 事件处理函数,例如:
1
| <input type="button" value="按钮" v-on:click="事件处理函数名" />
|
绑定事件处理函数并传参:
1
| <input type="button" value="按钮" v-on:click="show(123)" />
|
简写形式:
v-on:
指令可以简写成 @
,例如,可以简写成如下格式:
1
| <input type="button" value="按钮" @click="事件处理函数名" />
|
8.7 【案例】跑马灯效果
8.8 Vue 指令之 v-model
实现 双向数据绑定
- 基本使用:
- 和
v-bind:
的区别:
v-bind:
只能实现单向的数据同步 data ---> 页面
;
v-model
可以实现双向的数据同步 data <--> 页面
;
- 注意:
v-model
只能 和 表单元素 配合使用,例如 input、select、textarea
等;
v-model
是 Vue 中 唯一支持 双向数据绑定的指令;
- 应用场景:
- 【案例】自动计算文本框中,字符串的长度
- 【案例】简易加法计算器
8.9 在 Vue 中使用 class 样式
类名数组:
- 通过
v-bind:
为元素的 class
绑定具体的类名:
1
| <p :class="['thin', 'red', 'big']">彬哥最帅</p>
|
类名数组中使用三元表达式,按需为元素添加某些类名
1
| <p :class="['thin', flag ? 'red' : '']">彬哥最帅a a a</p>
|
应用场景
Vue 常用特性
表单基本操作
获取单选框中的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
<input type="radio" id="male" value="1" v-model="gender" /> <label for="male">男</label>
<input type="radio" id="female" value="2" v-model="gender" /> <label for="female">女</label>
<script> new Vue({ data: { gender: 2, }, }); </script>
|
获取复选框中的值
- 通过 v-model
- 和获取单选框中的值一样
- 复选框
checkbox
这种的组合时 data 中的 hobby 我们要定义成数组 否则无法实现多选
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
<div> <span>爱好:</span> <input type="checkbox" id="ball" value="1" v-model="hobby" /> <label for="ball">篮球</label> <input type="checkbox" id="sing" value="2" v-model="hobby" /> <label for="sing">唱歌</label> <input type="checkbox" id="code" value="3" v-model="hobby" /> <label for="code">写代码</label> </div> <script> new Vue({ data: { hobby: ["2", "3"], }, }); </script>
|
获取下拉框和文本框中的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <div> <span>职业:</span>
<select v-model="occupation" multiple> <option value="0">请选择职业...</option> <option value="1">教师</option> <option value="2">软件工程师</option> <option value="3">律师</option> </select> <textarea v-model="desc"></textarea> </div> <script> new Vue({ data: { occupation: ["2", "3"], desc: "nihao", }, }); </script>
|
表单修饰符
自定义指令
- 内置指令不能满足我们特殊的需求
- Vue 允许我们自定义指令
Vue.directive 注册全局指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
<input type="text" v-focus /> <script>
Vue.directive("focus", { inserted: function (el) { el.focus(); }, }); new Vue({ el: "#app", }); </script>
|
Vue.directive 注册全局指令 带参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <input type="text" v-color="msg" /> <script type="text/javascript">
Vue.directive("color", { bind: function (el, binding) { el.style.backgroundColor = binding.value.color; }, }); var vm = new Vue({ el: "#app", data: { msg: { color: "blue", }, }, }); </script>
|
自定义指令局部指令
- 局部指令,需要定义在 directives 的选项 用法和全局用法一样
- 局部指令只能在当前组件里面使用
- 当全局指令和局部指令同名时以局部指令为准
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <input type="text" v-color="msg" /> <input type="text" v-focus /> <script type="text/javascript">
var vm = new Vue({ el: "#app", data: { msg: { color: "red", }, }, directives: { color: { bind: function (el, binding) { el.style.backgroundColor = binding.value.color; }, }, focus: { inserted: function (el) { el.focus(); }, }, }, }); </script>
|
计算属性 computed
- 模板中放入太多的逻辑会让模板过重且难以维护 使用计算属性可以让模板更加的简洁
- 计算属性是基于它们的响应式依赖进行缓存的
- computed 比较适合对多个变量或者对象进行处理后返回一个结果值,也就是数多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <div id="computed-basics"> <p>Has published books:</p> <span>{{ publishedBooksMessage }}</span> </div>
<script> Vue.createApp({ data() { return { author: { name: "John Doe", books: [ "Vue 2 - Advanced Guide", "Vue 3 - Basic Guide", "Vue 4 - The Mystery", ], }, }; }, computed: { publishedBooksMessage() { return this.author.books.length > 0 ? "Yes" : "No"; }, }, }).mount("#computed-basics"); </script>
|
侦听器 watch
- 使用 watch 来响应数据的变化
- 一般用于异步或者开销较大的操作
- watch 中的属性 一定是 data 中 已经存在的数据
- 当需要监听一个对象的改变时,普通的 watch 方法无法监听到对象内部属性的改变,只有 data 中的数据才能够监听到变化,此时就需要 deep 属性对对象进行深度监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <!doctype html> <html lang="zh-cn"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="lib/vue3.0.global.js"></script> </head>
<body> <div id="app"> <div> <span>名:</span> <span> <input type="text" v-model="firstName" /> </span> </div> <div> <span>姓:</span> <span> <input type="text" v-model="lastName" /> </span> </div> <div>{{fullName}}</div> </div>
<script type="text/javascript"> let vm = Vue.createApp({ data() { return { firstName: "Jim", lastName: "Green", }; }, watch: { firstName: function (val) { this.fullName = val + " " + this.lastName; }, lastName: function (val) { this.fullName = this.firstName + " " + val; }, }, }); vm.mount("#app"); </script> </body> </html>
|
过滤器
- Vue.js 允许自定义过滤器,可被用于一些常见的文本格式化。
- 过滤器可以用在两个地方:双花括号插值和 v-bind 表达式。
- 过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示
- 支持级联操作
- 过滤器不改变真正的
data
,而只是改变渲染的结果,并返回过滤后的版本
- 全局注册时是 filter,没有 s 的。而局部过滤器是 filters,是有 s 的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <div id="app"> <input type="text" v-model="msg" /> <div>{{msg | upper}}</div>
<div>{{msg | upper | lower}}</div> <div :abc="msg | upper">测试数据</div> </div>
<script type="text/javascript"> Vue.filter("lower", function (val) { return val.charAt(0).toLowerCase() + val.slice(1); }); var vm = new Vue({ el: "#app", data: { msg: "", }, filters: { upper: function (val) { return val.charAt(0).toUpperCase() + val.slice(1); }, }, }); </script>
|
过滤器中传递参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <div id="box">
{{ message | filterA('arg1', 'arg2') }} </div> <script> Vue.filter("filterA", function (n, a, b) { if (n < 10) { return n + a; } else { return n + b; } });
new Vue({ el: "#box", data: { message: "哈哈哈", }, }); </script>
|
生命周期
- 事物从出生到死亡的过程
- Vue 实例从创建 到销毁的过程 ,这些过程中会伴随着一些函数的自调用。我们称这些函数为钩子函数
####常用的 钩子函数
beforeCreate |
在实例初始化之后,数据观测和事件配置之前被调用 此时 data 和 methods 以及页面的 DOM 结构都没有初始化 什么都做不了 |
created |
在实例创建完成后被立即调用此时 data 和 methods 已经可以使用 但是页面还没有渲染出来 |
beforeMount |
在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已 |
mounted |
el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。 数据已经真实渲染到页面上 在这个钩子函数里面我们可以使用一些第三方的插件 |
beforeUpdate |
数据更新时调用,发生在虚拟 DOM 打补丁之前。 页面上数据还是旧的 |
updated |
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。 页面上数据已经替换成最新的 |
beforeDestroy |
实例销毁之前调用 |
destroyed |
实例销毁后调用 |
数组变异方法
- 在 Vue 中,直接修改对象属性的值无法触发响应式。当你直接修改了对象属性的值,你会发现,只有数据改了,但是页面内容并没有改变
- 变异数组方法即保持数组方法原有功能不变的前提下对其进行功能拓展
push() |
往数组最后面添加一个元素,成功返回当前数组的长度 |
pop() |
删除数组的最后一个元素,成功返回删除元素的值 |
shift() |
删除数组的第一个元素,成功返回删除元素的值 |
unshift() |
往数组最前面添加一个元素,成功返回当前数组的长度 |
splice() |
有三个参数,第一个是想要删除的元素的下标(必选),第二个是想要删除的个数(必选),第三个是删除 后想要在原位置替换的值 |
sort() |
sort() 使数组按照字符编码默认从小到大排序,成功返回排序后的数组 |
reverse() |
reverse() 将数组倒序,成功返回倒序后的数组 |
替换数组
filter |
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。 |
concat |
concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组 |
slice |
slice() 方法可从已有的数组中返回选定的元素。该方法并不会修改数组,而是返回一个子数组 |
动态数组响应式数据
- Vue.set(a,b,c) 让 触发视图重新更新一遍,数据动态起来
- a 是要更改的数据 、 b 是数据的第几项、 c 是更改后的数据
图书列表案例
- 静态列表效果
- 基于数据实现模板效果
- 处理每行的操作按钮
1、 提供的静态数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| var vm = new Vue({ el: "#app", data: { books: [ { id: 1, name: "三国演义", date: "", }, { id: 2, name: "水浒传", date: "", }, { id: 3, name: "红楼梦", date: "", }, { id: 4, name: "西游记", date: "", }, ], }, }); var vm = new Vue({ el: "#app", data: { books: [ { id: 1, name: "三国演义", date: "", }, { id: 2, name: "水浒传", date: "", }, { id: 3, name: "红楼梦", date: "", }, { id: 4, name: "西游记", date: "", }, ], }, });
|
2、 把提供好的数据渲染到页面上
- 利用 v-for 循环 遍历 books 将每一项数据渲染到对应的数据中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <tbody> <tr :key="item.id" v-for="item in books"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.date}}</td> <td> <a href="" @click.prevent>修改</a> <span>|</span> <a href="" @click.prevent>删除</a> </td> </tr> </tbody>
|
3、 添加图书
- 通过双向绑定获取到输入框中的输入内容
- 给按钮添加点击事件
- 把输入框中的数据存储到 data 中的 books 里面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| <div> <h1>图书管理</h1> <div class="book"> <div> <label for="id"> 编号: </label> <input type="text" id="id" v-model="id" /> <label for="name"> 名称: </label> <input type="text" id="name" v-model="name" /> <button @click="handle">提交</button> </div> </div> </div> <script type="text/javascript">
var vm = new Vue({ el: "#app", data: { id: "", name: "", books: [ { id: 1, name: "三国演义", date: "", }, { id: 2, name: "水浒传", date: "", }, { id: 3, name: "红楼梦", date: "", }, { id: 4, name: "西游记", date: "", }, ], }, methods: { handle: function () { var book = {}; book.id = this.id; book.name = this.name; book.date = ""; this.books.push(book); this.id = ""; this.name = ""; }, }, }); </script>
|
4 修改图书-上
- 点击修改按钮的时候 获取到要修改的书籍名单
- 4.1 给修改按钮添加点击事件, 需要把当前的图书的 id 传递过去 这样才知道需要修改的是哪一本书籍
- 把需要修改的书籍名单填充到表单里面
- 4.2 根据传递过来的 id 查出 books 中 对应书籍的详细信息
- 4.3 把获取到的信息填充到表单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| <div id="app"> <div class="grid"> <div> <h1>图书管理</h1> <div class="book"> <div> <label for="id"> 编号: </label> <input type="text" id="id" v-model="id" :disabled="flag" /> <label for="name"> 名称: </label> <input type="text" id="name" v-model="name" /> <button @click="handle">提交</button> </div> </div> </div> <table> <thead> <tr> <th>编号</th> <th>名称</th> <th>时间</th> <th>操作</th> </tr> </thead> <tbody> <tr :key="item.id" v-for="item in books"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.date}}</td> <td>
<a href="" @click.prevent="toEdit(item.id)">修改</a> <span>|</span> <a href="" @click.prevent>删除</a> </td> </tr> </tbody> </table> </div> </div> <script type="text/javascript">
var vm = new Vue({ el: "#app", data: { flag: false, id: "", name: "", books: [ { id: 1, name: "三国演义", date: "", }, { id: 2, name: "水浒传", date: "", }, { id: 3, name: "红楼梦", date: "", }, { id: 4, name: "西游记", date: "", }, ], }, methods: { handle: function () { var book = {}; book.id = this.id; book.name = this.name; book.date = ""; this.books.push(book); this.id = ""; this.name = ""; }, toEdit: function (id) { console.log(id); var book = this.books.filter(function (item) { return item.id == id; }); console.log(book); this.id = book[0].id; this.name = book[0].name; }, }, }); </script>
|
5 修改图书-下
- 5.1 定义一个标识符, 主要是控制 编辑状态下当前编辑书籍的 id 不能被修改 即 处于编辑状态下 当前控制书籍编号的输入框禁用
- 5.2 通过属性绑定给书籍编号的 绑定 disabled 的属性 flag 为 true 即为禁用
- 5.3 flag 默认值为 false 处于编辑状态 要把 flag 改为 true 即当前表单为禁用
- 5.4 复用添加方法 用户点击提交的时候依然执行 handle 中的逻辑如果 flag 为 true 即 表单处于不可输入状态 此时执行的用户编辑数据数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| <div id="app"> <div class="grid"> <div> <h1>图书管理</h1> <div class="book"> <div> <label for="id"> 编号: </label> <input type="text" id="id" v-model="id" :disabled="flag" /> <label for="name"> 名称: </label> <input type="text" id="name" v-model="name" /> <button @click="handle">提交</button> </div> </div> </div> <table> <thead> <tr> <th>编号</th> <th>名称</th> <th>时间</th> <th>操作</th> </tr> </thead> <tbody> <tr :key="item.id" v-for="item in books"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.date}}</td> <td> <a href="" @click.prevent="toEdit(item.id)">修改</a> <span>|</span> <a href="" @click.prevent>删除</a> </td> </tr> </tbody> </table> </div> </div> <script type="text/javascript"> var vm = new Vue({ el: "#app", data: { flag: false, id: "", name: "", }, methods: { handle: function () {
if (this.flag) { this.books.some((item) => { if (item.id == this.id) { item.name = this.name; return true; } }); this.flag = false; } else { var book = {}; book.id = this.id; book.name = this.name; book.date = ""; this.books.push(book); this.id = ""; this.name = ""; } this.id = ""; this.name = ""; }, toEdit: function (id) {
this.flag = true; console.log(id); var book = this.books.filter(function (item) { return item.id == id; }); console.log(book); this.id = book[0].id; this.name = book[0].name; }, }, }); </script>
|
6 删除图书
- 6.1 给删除按钮添加事件 把当前需要删除的书籍 id 传递过来
- 6.2 根据 id 从数组中查找元素的索引
- 6.3 根据索引删除数组元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <tbody> <tr :key="item.id" v-for="item in books"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.date}}</td> <td> <a href="" @click.prevent="toEdit(item.id)">修改</a> <span>|</span> <a href="" @click.prevent="deleteBook(item.id)">删除</a> </td> </tr> </tbody> <script type="text/javascript"> /* 图书管理-添加图书 */ var vm = new Vue({ methods: { deleteBook: function(id){ // 删除图书 #// 6.2 根据id从数组中查找元素的索引 // var index = this.books.findIndex(function(item){ // return item.id == id; // }); #// 6.3 根据索引删除数组元素 // this.books.splice(index, 1); // ------------------------- #// 方法二:通过filter方法进行删除
# 6.4 根据filter 方法 过滤出来id 不是要删除书籍的id # 因为 filter 是替换数组不会修改原始数据 所以需要 把 不是要删除书籍的id 赋值给 books this.books = this.books.filter(function(item){ return item.id != id; }); } } }); </script>
|
常用特性应用场景
1 过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| <tr :key="item.id" v-for="item in books"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.date | format('yyyy-MM-dd hh:mm:ss')}}</td> <td> <a href="" @click.prevent="toEdit(item.id)">修改</a> <span>|</span> <a href="" @click.prevent="deleteBook(item.id)">删除</a> </td> </tr>
<script> #1.1 Vue.filter 定义一个全局过滤器 Vue.filter('format', function(value, arg) { function dateFormat(date, format) { if (typeof date === "string") { var mts = date.match(/(\/Date\((\d+)\)\/)/); if (mts && mts.length >= 3) { date = parseInt(mts[2]); } } date = new Date(date); if (!date || date.toUTCString() == "Invalid Date") { return ""; } var map = { "M": date.getMonth() + 1, //月份 "d": date.getDate(), //日 "h": date.getHours(), //小时 "m": date.getMinutes(), //分 "s": date.getSeconds(), //秒 "q": Math.floor((date.getMonth() + 3) / 3), //季度 "S": date.getMilliseconds() //毫秒 }; format = format.replace(/([yMdhmsqS])+/g, function(all, t) { var v = map[t]; if (v !== undefined) { if (all.length > 1) { v = '0' + v; v = v.substr(v.length - 2); } return v; } else if (t === 'y') { return (date.getFullYear() + '').substr(4 - all.length); } return all; }); return format; } return dateFormat(value, arg); }) #1.2 提供的数据 包含一个时间戳 为毫秒数 [{ id: 1, name: '三国演义', date: 2525609975000 },{ id: 2, name: '水浒传', date: 2525609975000 },{ id: 3, name: '红楼梦', date: 2525609975000 },{ id: 4, name: '西游记', date: 2525609975000 }]; </script>
|
2 自定义指令
- 让表单自动获取焦点
- 通过 Vue.directive 自定义指定
1 2 3 4 5 6 7 8 9 10 11
| <input type="text" id="id" v-model="id" :disabled="flag" v-focus />
<script> # 2.1 通过Vue.directive 自定义指定 Vue.directive('focus', { inserted: function (el) { el.focus(); } }); </script>
|
3 计算属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <div class="total"> <span>图书总数:</span> <span>{{total}}</span> </div>
<script type="text/javascript">
var vm = new Vue({ data: { flag: false, submitFlag: false, id: "", name: "", books: [], }, computed: { total: function () { return this.books.length; }, }, }); </script>
|
生命周期
组件
组件
- 组件 (Component) 是 Vue.js 最强大的功能之一
- 组件可以扩展 HTML 元素,封装可重用的代码
组件注册
全局注册
- vm.component(‘组件名称’, { }) 第 1 个参数是标签名称,第 2 个参数是一个选项对象
- 全局组件注册后,任何vue 实例都可以用
组件基础用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <div id="example"> <my-component></my-component> </div> <script> Vue.component("my-component", { template: "<div>A custom component!</div>", });
new Vue({ el: "#example", }); </script>
|
组件注意事项
- 组件参数的 data 值必须是函数同时这个函数要求返回一个对象
- 组件模板必须是单个根元素
- 组件模板的内容可以是模板字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| <div id="app">
<button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> <hello-world></hello-world> </div>
<script type="text/javascript"> Vue.component("HelloWorld", { data: function () { return { msg: "HelloWorld", }; }, template: "<div>{{msg}}</div>", });
Vue.component("button-counter", { data: function () { return { count: 0, }; }, template: ` <div> <button @click="handle">点击了{{count}}次</button> <button>测试123</button> # 6 在字符串模板中可以使用驼峰的方式使用组件 <HelloWorld></HelloWorld> </div> `, methods: { handle: function () { this.count += 2; }, }, }); var vm = new Vue({ el: "#app", data: {}, }); </script>
|
局部注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <div id="app"> <my-component></my-component> </div>
<script> var Child = { template: "<div>A custom component!</div>", }; new Vue({ components: { "my-component": Child, }, }); </script>
|
Vue 调试工具
Vue 组件之间传值
父组件向子组件传值
- 父组件发送的形式是以属性的形式绑定值到子组件身上。
- 然后子组件用属性 props 接收
- 在 props 中使用驼峰形式,模板中需要使用短横线的形式字符串形式的模板中没有这个限制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <div id="app"> <div>{{pmsg}}</div> <menu-item title="来自父组件的值"></menu-item>
<menu-item :title="ptitle" content="hello"></menu-item> </div>
<script type="text/javascript"> Vue.component("menu-item", { props: ["title", "content"], data: function () { return { msg: "子组件本身的数据", }; }, template: '<div>{{msg + "----" + title + "-----" + content}}</div>', }); var vm = new Vue({ el: "#app", data: { pmsg: "父组件中内容", ptitle: "动态绑定属性", }, }); </script>
|
子组件向父组件传值
- 子组件用
$emit()
触发事件
$emit()
第一个参数为 自定义的事件名称 第二个参数为需要传递的数据
- 父组件用 v-on 监听子组件的事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <div id="app"> <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
<menu-item :parr="parr" @enlarge-text="handle($event)"></menu-item> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript"> /* 子组件向父组件传值-携带参数 */
Vue.component("menu-item", { props: ["parr"], template: ` <div> <ul> <li :key='index' v-for='(item,index) in parr'>{{item}}</li> </ul> ### 1、子组件用$emit()触发事件 ### 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据 <button @click='$emit("enlarge-text", 5)'>扩大父组件中字体大小</button> <button @click='$emit("enlarge-text", 10)'>扩大父组件中字体大小</button> </div> `, }); var vm = new Vue({ el: "#app", data: { pmsg: "父组件中内容", parr: ["apple", "orange", "banana"], fontSize: 10, }, methods: { handle: function (val) { // 扩大字体大小 this.fontSize += val; }, }, }); </script>
|
兄弟之间的传递
- 兄弟之间传递数据需要借助于事件中心,通过事件中心传递数据
- 提供事件中心 var hub = new Vue()
- 传递数据方,通过一个事件触发 hub.$emit(方法名,传递的数据)
- 接收数据方,通过 mounted(){} 钩子中 触发 hub.$on()方法名
- 销毁事件 通过 hub.$off()方法名销毁之后无法进行传递数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| <div id="app"> <div>父组件</div> <div> <button @click="handle">销毁事件</button> </div> <test-tom></test-tom> <test-jerry></test-jerry> </div> <script type="text/javascript" src="js/vue.js"></script> <script type="text/javascript">
var hub = new Vue();
Vue.component("test-tom", { 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; }); }, }); Vue.component("test-jerry", { 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; }); }, }); var vm = new Vue({ el: "#app", data: {}, methods: { handle: function () { hub.$off("tom-event"); hub.$off("jerry-event"); }, }, }); </script>
|
vue-cli
安装与启动
1 2 3 4 5 6 7 8 9 10 11 12
| npm install -g @vue/cli
yarn global add @vue/cli
npm install -g @vue/cli @vue/cli-service-global
yarn global add @vue/cli @vue/cli-service-global
vue create 项目名称
|
使用 sass 全局方法 @mixnin
- 先运行 vue add style-resources-loader
配置 vue.config.js
1 2 3 4 5 6 7 8 9 10
| const path = require("path"); module.exports = { pluginOptions: { "style-resources-loader": { preProcessor: "scss", patterns: [path.resolve(__dirname, "./src/mixnin.scss")] } } };
|
样式穿透
https://github.com/vuejs/rfcs/blob/master/active-rfcs/0023-scoped-styles-changes.md
vue-router
安装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| npm install vue-router@next
├─.browserslistrc ├─.eslintrc.js ├─.gitignore ├─babel.config.js ├─package.json ├─README.md ├─yarn.lock ├─src | ├─App.vue | ├─main.js | ├─routes | | └index.js | ├─components | | └HelloWorld.vue | ├─assets | | └logo.png ├─public | ├─favicon.ico | └index.html
|
配置文件书写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
import { createRouter, createWebHashHistory } from "vue-router";
import HelloWorld from "../components/HelloWorld"; const routes = [ { name: "home", path: "/home", component: HelloWorld, }, ];
const router = createRouter({ history: createWebHashHistory(), routes, });
export default router;
|
main.js 文件的书写
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
import { createApp } from "vue"; import App from "./App.vue";
import routes from "./routes"; createApp(App) .use(routes) .mount("#app");
|
路由重定向 router-redirect
1 2 3 4 5 6 7 8
| let routes = [ { path: "原路由", redirect: "要跳转到哪个路由", }, { 其他路由规则 }, ];
|
嵌套路由 router-nest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| let routes = [ { path: "父组件路由规则", component: "组件名", children: [ { path: "父组件路由规则", component: "组件名", }, ], }, ];
|
路由传参 router-dynamic
直接接收
在路由规则中
1 2 3 4 5 6 7
| let routes = [ { path: "父组件路由规则/:占位符名称", component: "组件名", }, ];
|
在对应组件中
1 2 3 4 5 6 7 8 9 10 11
| <template> <div> <p>{{ $router.params.占位符名称 }}</p> </div> </template>
<script> export default {}; </script>
<style></style>
|
通过 props 属性
在路由规则中
1 2 3 4 5 6 7 8
| let routes = [ { path: "父组件路由规则/:占位符名称", component: "组件名", props: true, }, ];
|
在对应组件中
1 2 3 4 5 6 7 8 9 10 11 12 13
| <template> <div> <p>{{ 占位符名称 }}</p> </div> </template>
<script> export default { props: ["占位符名称"], }; </script>
<style></style>
|
通过回调函数
在路由规则中
1 2 3 4 5 6 7 8 9
| let routes = [ { path: "父组件路由规则/:占位符名称", component: "组件名", props: router=>({属性名: router.params.占位符名称,属性名:属性值,...}) } ]
|
在对应组件中
1 2 3 4 5 6 7 8 9 10 11 12 13
| <template> <div> <p>{{ 属性名 }}</p> </div> </template>
<script> export default { props: ["属性名","属性名",...] }; </script>
<style></style>
|
编程式导航 router-program
命名路由
在路由规则中
1 2 3 4 5 6 7
| let routes = [ { name: "路由的名字" path: "父组件路由规则/:占位符名称", component: "组件名", } ]
|
在对应组件中
1 2 3 4 5 6 7 8 9 10 11 12
| <template> <!-- 如果传入了参数记得去router/index.js里面开启props --> <router-link :to="{ name: '路由的名字', params: { 属性名: 属性值 } }" >超链接</router-link > </template>
<script> export default {}; </script>
<style></style>
|
Vuex 统一状态管理
VueX 概述
为什么要学习 VueX
父向子传值:父元素 v-bind 属性绑定数据,子元素使用 props 接受父元素传递的数据
子向父传值:父元素 v-on 事件绑定,子元素使用$emit 触发,并通过回调函数把值传递给父元素
兄弟组件之间共享数据:EventBus(mitt)
emitter.on() 接收数据的那个组件
emitter.emit() 发送数据的那个组件
VueX 简介
.
Vuex 是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的数据共享
使用 Vuex 管理数据的好处:
A.能够在 vuex 中集中管理共享的数据,便于开发和后期进行维护
B.能够高效的实现组件之间的数据共享,提高开发效率
C.存储在 vuex 中的数据是响应式的,当数据发生改变时,页面中的数据也会同步更新
注意,不是任何数据都适合放在vuex中的,一般情况下,只有组件之间共享的数据,才有必要存储到vuex 中;对于组件中的私有数据,依旧存储在组件自身的data 中即可
VueX 的基本使用
1.安装
1 2
| # If using Vue 3.0 + Vuex 4.0: npm install vuex@next --save
|
2.配置(store/index.js)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { createStore } from "vuex";
export default createStore({ state() { return {}; }, mutations: {}, actions: {}, getters: {}, });
|
3.挂载(src/main.js)
1 2 3 4
| import { createApp } from "vue"; import App from "./App.vue"; import store from "./store"; createApp(App).use(store).mount("#app");
|
VueX 的核心概念
State(类似于 Vue 中的 data 选项)
State 提供唯一的公共数据源,所有共享的数据都要统一放到 Store 的 State 中进行存储
定义语法:
1 2 3 4 5 6 7
| const store = createStore({ state() { return { 属性名: 属性值, }; }, });
|
访问:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| this.$store.state.全局数据属性名
import { createStore } from "vuex";
export default createStore({ state() { return { count: 0, msg: "Welcome to Your Vue2" }; }, mutations: {}, actions: {}, modules: {} });
<script> import { mapState } from "vuex"; export default { name: "HelloWorld", computed: { ...mapState(["count", "msg"]) } }; </script>
|
mutation 相当于 Vue 中 methods
Mutation 用于修改 Store 中的数据。 1.只能通过 mutation 变更 Store 数据,不可以直接操作 Store 中的数据。 2.通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。
方法 1(未传参数)
1.store/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { createStore } from "vuex";
export default createStore({ state() { return { aname: "张三", }; }, mutations: { changeName(state) { state.aname = "李四"; }, }, });
|
2.在某一个组件文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| // 触发mutation <template> <div class="hello"> <h1 @click="changeName">{{ msg }}</h1> </div> </template>
<script> import { mapState, mapMutations } from "vuex"; export default { name: "HelloWorld", props: { msg: String, }, data() { return { name: "我最喜欢福原爱", }; }, // created(){ // this.handleChange(); // }, methods: { // 这个方法是用来触发store中的mutations中的changeName方法的 handleChange() { this.$store.commit("changeName"); }, }, computed: { ...mapState(["aname"]), }, }; </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
|
方法 2(传参数)
1.store/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { createStore } from "vuex";
export default createStore({ state() { return { aname: "张三", }; }, mutations: { changeOtherName(state, name1) { state.aname = name1; }, }, });
|
2.在某一个组件文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| <template> <div class="hello"> <h1 @click="changeName">{{ msg }}</h1> <h2 @click="changeOtherName(name)">{{aname}}</h2> </div> </template>
<script> import {mapState,mapMutations} from "vuex" export default { name: "HelloWorld", props: { msg: String }, data(){ return { name: "我最喜欢福原爱" } }, methods: { handelOtherChange(){ let name = this.name; this.$store.commit("changeOtherName",name); } ...mapMutations(['changeName','changeOtherName']) }, computed: { ...mapState(['aname']) } }; </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
|
方法 3
1.store/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { createStore } from "vuex";
export default createStore({ state() { return { aname: "张三", }; }, mutations: { changeName(state) { state.aname = "李四"; }, changeOtherName(state, name1) { state.aname = name1; }, }, });
|
2.在某一个组件文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <template> <div class="hello"> <h1 @click="changeName">{{ msg }}</h1> <h2 @click="changeOtherName(name)">{{aname}}</h2> </div> </template>
<script> import {mapState,mapMutations} from "vuex" export default { name: "HelloWorld", props: { msg: String }, data(){ return { name: "我最喜欢福原爱" } }, methods: { ...mapMutations(['changeName','changeOtherName']) }, computed: { ...mapState(['aname']) } }; </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
|
action 用于异步处理数据
Action 用于处理异步任务。
如果通过异步操作变更数据,必须通过 Action,而不能使用 Mutation,
但是在 Action 中还是要通过触发 Mutation 的方式间接变更数据。
方法 1
1.store/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import { createStore } from "vuex";
export default createStore({ state() { return { count: 0, }; }, mutations: { add(state, val) { state.count += val; }, }, actions: { asyncAdd(context, val) { console.log(context); setInterval(function () { context.commit("add", val); }, 1000); }, }, getters: {}, });
|
2.在某一个组件中
1 2 3 4 5 6 7
| methods: { handle() { this.$store.dispatch('addNAsync', 5) } }
|
方法 2
2.在某一个组件中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <template> <div class="hello"> <h1 @click="asyncAdd(2)">{{ msg }}</h1> <p>{{ count }}</p> </div> </template>
<script> import { mapState, mapActions } from "vuex"; export default { name: "HelloWorld", props: { msg: String }, computed: { ...mapState(["count"]) }, methods: { ...mapActions(["asyncAdd"]) } }; </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
|
getter 相当于 Vue 中 computed
Getter 用于对 Store 中的数据进行加工处理形成新的数据。
1.Getter 可以对 Store 中已有的数据加工处理之后形成新的数据,类似 Vue 的计算属性。
2.Store 中数据发生变化,Getter 的数据也会跟着变化
方法 1
1.store/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import { createStore } from "vuex";
export default createStore({ state() { return { count: 0, }; }, mutations: { add(state) { state.count++; }, }, actions: {}, getters: { num(state) { return state.count; }, }, });
|
2.在某一个组件中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <template> <div class="hello"> <h1>{{ msg }}</h1> <button @click="add">点我让数字自增{{num}}</button> </div> </template>
<script> import {mapMutations,mapGetters} from "vuex" export default { name: "HelloWorld", props: { msg: String }, methods: { ...mapMutations(['add']) }, computed: { ...mapGetters(['num']) } }; </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
|
https://www.v2ex.com/t/347227 > https://bigdata.bihell.com/language/javascript/vue/vuex.html#揭开-vuex-的神秘面纱 > https://cn.vuejs.org/v2/guide/state-management.html#简单状态管理起步使用
总结
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import { createStore } from "vuex";
export default createStore({ state() { return { str: "123", }; }, mutations: { editStr(state, payload) { state.str = payload; }, }, actions: { asyncEditStr(context, payload) { context.commit("editStr", payload); }, }, modules: {}, });
|
vue-compositionAPI 的使用
定义变量 ref、reactive
- ref 定义简单数据类型
- reactive 定义复杂数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <template> <div class="box"> <h1>这里相当于 optionsAPI里面的data</h1> <div>{{ hello }}</div> <div>{{ obj }}</div> </div> </template>
<script> // 注意要引入vue里面的方法才可以使用 import { reactive, ref } from "vue"; export default { name: "App", // components: {} setup() { let hello = ref("hello"); let obj = reactive({ name: "罗老师", age: 18, }); // 导出变量 return { hello, obj, }; }, }; </script>
<style scoped> .box { text-align: center; background-color: skyblue; } </style>
|
方法的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <template> <div class="box"> <h1>这里相当于 optionsAPI里面的 methods</h1> <h2> 您将学习到修改 ref 和 reactive 里面的值和使用 在compositions里面使用optionsAPI里面的methods </h2> <div>{{ hello }}</div> <div>{{ obj }}</div> <button @click="changeName">点击我修改值</button> </div> </template>
<script> import { reactive, ref } from "vue"; export default { name: "App", // components: {} setup() { let hello = ref("hello"); let obj = reactive({ name: "罗老师别这样", age: 18, });
function changeName() { hello.value = "不hello"; obj.name = "罗老师"; } // 导出 return { hello, obj, changeName, }; }, }; </script>
<style scoped> .box { text-align: center; background-color: pink; } </style>
|
watch 监听值的变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <template> <div class="box"> <h1>这里相当于 optionsAPI里面的 watch</h1> <h2> 您将学习到在compositions里面使用optionsAPI里面的watch 注意看控制台 </h2> <div>{{ num }}--{{ num2 }}</div> <button @click="changeNum">点击我数字变化</button> </div> </template>
<script> import { ref, watch } from "vue"; export default { name: "App", setup() { let num = ref(100); let num2 = ref(200);
function changeNum() { setInterval(() => { num.value++; num2.value++; }, 500); } watch( () => num.value, (count, prevCount) => { console.log("num 变化后的值", count, "num 变化前的值", prevCount); } ); watch( [num, num2], ([num, num2], [prevNum, prevNum2]) => { console.log("num 变化后的值", num, "num 变化前的值", prevNum); console.log("num2 变化后的值", num2, "num2 变化前的值", prevNum2); } ); return { num, num2, changeNum }; } }; </script>
<style scoped> .box { text-align: center; background-color: skyblue; } </style>
|
watchEffect
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| <template> <div class="box"> <h1>这里相当于 optionsAPI里面的 watch</h1> <h2>您将学习到在compositions里面使用optionsAPI里面的watch 注意看控制台</h2> <div>{{ num }}--{{ num2 }}</div> <button @click="changeNum">点击我数字变化</button> </div> </template>
<script> import { ref, watchEffect } from "vue"; export default { name: "App", // components: {} setup() { let num = ref(100); let num2 = ref(200);
function changeNum() { setInterval(() => { num.value++; num2.value++; }, 500); }
//监听多个值 watchEffect(() => { console.log(num.value); console.log(num2.value); });
// 导出 return { num, num2, changeNum, }; }, }; </script>
<style scoped> .box { text-align: center; background-color: pink; } </style>
|
computed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <template> <div class="box"> <h1>这里相当于 optionsAPI 里面的 computed</h1> <h2>注意看控制台</h2> <div>helloComputed={{ helloComputed }}</div> <div>numComputed={{ numComputed }}</div> </div> </template>
<script> // 注意要引入vue里面的方法才可以使用 import { computed, ref } from "vue"; export default { name: "App", // components: {} setup() { let hello = ref("hello"); let helloComputed = computed(() => { return hello.value + "World"; //计算完毕之后变成helloWorld }); let num = ref(21); let numComputed = computed({ get: () => num.value + 11, //直接调用执行这里 set: (val) => { // 2.执行这里 console.log("numComputed.value=", val); }, }); // 1.给 numComputed 赋值 numComputed.value = 20; // 导出变量 return { helloComputed, numComputed, }; }, }; </script>
<style scoped> .box { text-align: center; background-color: skyblue; } </style>
|
调用 vuex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <template> <div class="box"> <h2>您将学习到修改 如何调用 vuex里面的值和方法</h2> <div>vuex里面的msg的值是---{{ msg }}</div> <div>vuex里面的msg被计算属性之后的值----{{ msgComputed }}</div> <button @click="changeMsg">点击修改vuex-msg</button> </div> </template>
<script> import { computed } from "vue"; import { useStore } from "vuex"; export default { name: "vuex", // components: {} setup() { let store = useStore(); //获取 state() 里面的属性 let msg = computed(() => store.state.msg); //获取 getters()里面的属性 let msgComputed = computed(() => store.getters.msg); function changeMsg() { // 调用mutations的方法 store.commit("changeMsg"); // 调用actios里面的方法 store.dispatch("fn"); } return { msg, changeMsg, msgComputed, }; }, }; </script>
<style scoped> .box { text-align: center; background-color: pink; } </style>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import { createStore } from "vuex";
export default createStore({ state() { return { msg: "here is vuex", }; }, mutations: { changeMsg(state) { state.msg = "msg被修改了"; }, }, actions: { async fn() { let a; setTimeout(() => { a = 90; }, 0); a = 90;
console.log(a); }, }, modules: {}, getters: { msg(state) { return state.msg + "计算属性"; }, }, });
|
vue 获取元素
https://blog.csdn.net/weixin_43233914/article/details/108776124
https://v3.cn.vuejs.org/guide/composition-api-template-refs.html#%E4%BE%A6%E5%90%AC%E6%A8%A1%E6%9D%BF%E5%BC%95%E7%94%A8
vue3 语法糖
rfcs/0000-script-setup.md at script-setup-2 · vuejs/rfcs (github.com)