# Vue(3)
# 6. 安装Vue Devtools
- 访问Vue插件——Vue Devtools (opens new window)或者GitHub网页 (opens new window)下载
- 点击Chrome浏览器的右上角三个点——更多工具——扩展程序
- 将.crx文件拖入Chrome的扩展程序中
- 点击插件的详情按钮,将“允许访问文件网址”的开关打开
# 7. 什么是vue
- 构建用户界面
- 用vue往html页面中填充数据,非常的方便
- 框架
- 框架是一套现成的解决方案,程序员只能遵守框架的规范,去编写自己的业务功能!
- 要学习vue,就是在学习vue框架中规定的用法!
- vue的指令、组件(是对UI结构的复用)、路由、Vuex、vue组件库
- vue的版本
当前,vue共有3个大版本,其中:
- 2.x版本的vue是目前企业级项目开发中的主流版本
- 3.x版本的vue于2020-09-19发布,生态还不完善,尚未在企业级项目开发中普及和推广
- 1.x版本的vue几乎被淘汰,不再建议学习与使用
- 总结:
- 3.x版本的vue是未来企业级项目开发的趋势;
- 2.x版本的vue在未来(1 ~ 2年内)会被逐渐淘汰;
# 8. vue的两个特性
数据驱动视图:
- 数据的变化会驱动视图自动更新
- 好处: 程序员只管把数据维护好,那么页面结构会被vue自动渲染出来!
- 注意:数据驱动视图是单向的数据绑定
双向数据绑定:
- 在网页中,form 表单负责采集数据,Ajax 负责提交数据。
- js数据的变化,会被自动渲染到页面上
- 页面上表单采集的数据发生变化的时候,会被vue自动获取到,并更新到js 数据中
- 好处:开发者不再需要手动操作DOM元素来获取表单最新的值
# 9. MVVM
MVVM是vue实现数据驱动视图和双向数据绑定的核心原理。MVVM指的是Model、 View和ViewModel,它把每个HTML页面都拆分成了这三个部分。
MVVM的组成
- Model表示当前页面渲染时所依赖的数据源。
- View表示当前页面所渲染的DOM结构。
- ViewModel表示vue的实例,它是MVVM的核心。
具体可参见下图:
# 10. Vue2 / Vue3的使用
- 导入vue.js的script脚本文件
- 在页面中声明一个将要被vue所控制的DOM区域
- 创建vm实例对象(vue 实例对象)
# 10.1 导入方式一
- 访问官方安装 (opens new window)页面,自行下载安装
- 或者点击下载开发版本vue.js (opens new window)或者生产版本vue.min.js (opens new window)文件,并导入该文件
<!-- Vue2 --> <div id="app">{{msg}}</div> <script src="./vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { msg: 'hello world!' } }) </script>
Copied!
# 10.2 导入方式二
<!-- Vue2 --> <!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <!-- 生产环境版本,优化了尺寸和速度 --> <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> <!-- Vue3 --> <script src="https://unpkg.com/vue@next"></script>
Copied!
# 10.3 导入方式三
在用 Vue 构建大型应用时推荐使用 NPM 安装。NPM 能很好地和诸如 webpack (opens new window) 或 Browserify (opens new window) 模块打包器配合使用。同时 Vue 也提供配套工具来开发单文件组件。
# vue2最新稳定版 $ npm install vue # vue3最新稳定版 $ npm install vue@next
Copied!
# 11. Vue的指令
# 11.1 插值语法
{{}}
: 数据绑定,既可以绑定基本数据类型,也可绑定对象、数组等类型; 同时也可以进行变量相加运算或者三目运算等
<body> <div id="root"> <!-- 视图层 v--> 插值表达式:渲染数据,基本运算,三元运算 {{msg}}{{numa+numb}}{{flag ? '真的':'假'}} <h1> {{newObj.name}}是一个{{newObj.age}}的{{newObj.job}} </h1> <h1> {{newArry[0]}}{{newArry[1]}}{{newArry[2]}} </h1> <div> <input type="text" v-model="value"> {{value}} </div> <h1>{{msg}}</h1> </div> <!-- {{msg}} --> <script> var vm = new Vue({//创建了一个vue的实例 vm el:"#root",//定位 data:{//数据源M msg:"hello world!", numa:1, numb:'2', flag:false, newObj:{ name:'张三', age:58, job:'程序员' }, newArry:['hello','vue',2], value:'' } }) </script> </body>
Copied!
# 11.2 v-text
v-text
: 会将原来的值覆盖,并设置文本值,相当于innerText
<body> <div id="root"> <!-- v-text:设置标签文本值 --> <h1>{{msg}}</h1> <!-- 可以将data的数据渲染在页面上 --> <h1 v-text="msg"></h1> <!-- 可以进行JavaScript逻辑运算 --> <h1 v-text="msg+'111'"></h1> <!-- 三目运算 --> <h1 v-text="1>2 ?'大于':'小于'"></h1> <!-- 字符串拼接 --> <h1 v-text="msg+msg"></h1> <h1>{{msg}}哈哈哈</h1> <h1 v-text="msg">哈哈哈</h1> <!-- <h1 v-text="ha">哈哈哈</h1> --> </div> <script> var vm = new Vue({//创建了一个vue的实例 vm el:"#root",//定位 data:{//数据源M msg:"hello world!" } }) </script> </body>
Copied!
# 11.3 v-html
v-html
: 会将原来的值覆盖,将字符串转为HTML
<body> <div id="root"> <!-- v-html 把字符串当作html渲染,类似与innerHTML --> <div v-html="msg"></div> <div v-cloak>{{msg}}</div> <div v-text="msg"></div> <!-- 字符串拼接 --> <div v-html="msg+'123456'"></div> <!-- 三目运算 --> <div v-html="3>2?msg:'1才不大于2'"></div> <div v-html="msg">哈哈哈</div> <!-- 3种方式可以去渲染数据: 1:{{}} 加载的时候会出现回闪,解决方法使用v-cloak(会出现{{msg}}) 2.v-text 会将中间的数据覆盖掉 3.v-html 会将中间的数据覆盖掉 --> </div> <script> var vm = new Vue({//创建了一个vue的实例 vm el:"#root",//定位 data:{//数据源M msg:"<h1>hello world!</h1>" } }) </script> </body>
Copied!
# 11.4 v-pre
v-pre
: 不编译,跳过绑定,直接显示
<body> <div id="root"> <div>{{msg}}</div> <!-- 不编译, --> <div v-pre>{{msg}}</div> </div> <script> var vm = new Vue({ el:"#root", data:{ msg:"<h1>hello world!</h1>" } }) </script> </body>
Copied!
# 11.5 v-once
v-once
: 不随变量值的改变而改变,即只在最开始的时候渲染一次
<body> <div id="root"> <div>{{msg}}</div> <div v-once>{{msg}}</div> </div> <script> var vm = new Vue({ el:"#root", data:{ msg:"hello world!" } }) </script> </body>
Copied!
# 11.6 v-cloak
v-cloak
: {{}} 加载的时候可以出现回闪,通常用v-clock解决,首先在标签上加上v-cloak,然后在style样式里加上[v-cloak] {display: none}
代码块。
<style> [v-cloak] { display: none; } </style> <body> <h1 v-cloak>{{msg}}</h1> <script> var vm = new Vue({ el:"#root", data:{ msg:"hello world!" } }) </script> </body>
Copied!
# 11.7 v-model(双向绑定)
v-model
:
- 双向绑定 v-model=“XXX”
- v-model="hobbies" / hobbies: []
- V-model.lazy: 在敲回车和失去焦点的时候才进行绑定
- v-model.number: 使字符串转为数字
- v-model.trim: 去除前后空格
注意
v-model指令一般与表单元素结合使用才有意义
修饰符 | 描述 |
---|---|
.lazy | 在敲回车和失去焦点的时候才进行绑定 |
.number | 使字符串转为数字 |
.trim | 去除前后空格 |
<body> <div id="root"> <div> <input type="text" v-model="value"> {{value}} </div> <input type="checkbox" v-model="hobby">爱好 {{hobby}} <!-- 值为true 或者 false --> <!-- 做一个点单 --> <div> <input type="checkbox" v-model="diandan" value="炸鸡">炸鸡 <input type="checkbox" v-model="diandan" value="烤鸭">烤鸭 <input type="checkbox" v-model="diandan" value="纸包鱼">纸包鱼 <input type="checkbox" v-model="diandan" value="蒜香花甲">蒜香花甲 <input type="checkbox" v-model="diandan" value="烤鱼">烤鱼 {{diandan}} </div> <!-- v-model修饰符 --> <div> <!-- 没有加修饰符 --> <input type="text" v-model="value"> {{value}} <!-- 加修饰符 .lazy--> <input type="text" v-model.lazy="value"> {{value}} <!-- 加修饰符 .number--> <input type="text" v-model.number="num"> {{num}} <!-- 加修饰符 .trim--> <!-- 去头去尾空格号 --> <input type="text" v-model.trim="value"> {{value}} <!-- 结合加修饰符 --> <input type="text" v-model.number.lazy="num"> {{num}} </div> </div> <script> var vm = new Vue({ el:"#root", data:{ value:'', hobby:'', diandan:[], num:0 } }) </script> </body>
Copied!
# 11.8 v-show / v-if / v-else
v-if/v-else
: 会把节点删除,只切换一次,大部分情况用这个
v-show
: 不会删除节点,只是多加了display:none,在隐藏与显示频繁切换
如果要频繁的切换元索的显示状态,用v-show性能会更好
如果刚进入页面的时候,某些元素默认不需要被展示,而且后期这个元素很可能也不需要被展示出来,此时v-if性能更好
<body> <div id="root"> <!-- js假值:false,0,'',nan,null,undefined --> <div v-show="false">{{msg}}</div> <div v-if="null">{{msg}}</div> <!-- 相同点:都能隐藏元素 不同点:v-show是切换元素display css属性,参加页面渲染 v-if是节点重新渲染或者销毁 --> <div> <div> <button @click="imgChange">切换图片</button> </div> <img v-show="change" src="#"> <img v-show="!change" src="#"> </div> <div> <h1 v-if="age<18">未成年</h1> <h1 v-else-if="age<30">青年</h1> <h1 v-else-if="age<60">正值壮年</h1> <h1 v-else>老年</h1> </div> </div> <script> var vm = new Vue({ el: "#root", data: { msg: '我又出现了', change: true, age:203 }, methods: { imgChange() { this.change = !this.change } }, }) </script> </body>
Copied!
# 11.9 v-for
v-for
:
- 循环遍历数组
"(item, index) in XXX"
- 遍历对象
"(value, key) in XXX"
<body> <div id="root"> <!-- 遍历数组 --> <ul> <li v-for="(item,index) in msg">{{index+1}}-{{item}}</li> </ul> <!-- 遍历对象 --> <ul> <li v-for="(item,index) in user">{{index}}-{{item}}</li> </ul> <li v-for="u in user.name">{{u}}</li> </div> <script> var vm = new Vue({ el: "#root", data: { msg: ["炸鸡","烤鸭","小黄鱼","烧烤"], user: { name: '张三', age: 18, hobby: "打官司" } } }) </script> </body>
Copied!
# 11.9.1 v-for使用时的建议
官方建议:只要用到了v-for指令,那么一定要绑定一个
:key
属性而且,尽量把id作为key的值,不要用index作为key
官方对key的值类型,是有要求的:字符串或数字类型
key的值是千万不能重复的,否则会终端报错: Duplicate keys detected*(重复的键被检测到)*
# 11.9.2 key的注意事项
- key 的值只能是字符串或数字类型
- key 的值必须具有唯一性(即: key 的值不能重复)
- 建议把数据项id属性的值作为key的值( 因为id属性的值具有唯一性 )
- 使用index的值当作key的值没有任何意义( 因为index的值不具有唯一性 )
- 建议使用v-for指令时一定要指定key的值(既提升性能、又防止列表状态紊乱)
# 11.10 v-bind
v-bind
:
- 属性绑定,可以简写为
:src="XXX"
相当于v-bind:src="XXX"
- 动态绑定class—— :class{类名1: 布尔值,类名2: 布尔值}
- 然后v-on:click="fn",在fn里改变布尔值
- :class='getClasses()',getClasses: function(){return {...}}
- 绑定样式——:style="{fontsize: size+'px'}"
- 在使用v-bind属性绑定期间,如果绑定内容需要进行动态拼接,则字符串的外面应该包裹单引号
<head> ...... <style> .activeA{ color: rgb(231,68,68); } .activeB{ font-size: 50px; } .activeC{ color: rgb(231,68,68); font-size: 50px; } </style> </head> <body> <div id="root"> <div class="ha" :class="{'activeA':isA,'activeB':isB}">{{msg}}</div> <div :style="{fontSize: fontSize, color: fontColor}"> {{msg}} </div> </div> <script> var vm = new Vue({ el: "#root", data: { msg:"真是知识点", isA:true, isB:false, isC:"activeC", fontSize: '50px', fontColor: 'red' } }) </script> </body>
Copied!
# 11.11 v-on
v-on
:
- 绑定事件v-on:click=""
- 语法糖:
@click=""
- @click.stop: 阻止冒泡e.stopPropagation()
- @click.prevent: 阻止默认事件 e.preventDefault()
- @keyup.enter: 输入回车
- @click.native: 组件监听
- @click.once: 点击回调只触发一次
- 在绑定事件处理函数的时候,可以使用() 传递参数,如果要传event则需要传递$event,如果只传入event时函数的参数可以不写
# 11.11.1 v-on基础用法
<body> <div id="root"> 你的颜值分数:{{count}} <button @click="add">加分</button> <button @click="minus">减分</button> </div> <script> var vm = new Vue({ el: "#root", data: { count:100 }, methods: { add(){ this.count++; }, minus(){ if(this.count <= 60){ alert('不能再减了,我只有内在美了') return } this.count--; } }, }) </script> </body>
Copied!
<!-- 传入event参数的实例 --> <body> <div id="root"> <div>值:{{ count }}</div> <button @click="add($event)">+1</button> <!-- <button @click="add">+1</button> --> <button @click="sub($event, 2)">-1</button> </div> <script> let vm = new new Vue({ el: "#root", data: { count: 0 }, methods: { add() { console.log(e); // e可以省略,传入的函数参数也可以省略,也可以像注释部分那样写 this.count++; }, sub(e, step) { console.log(e); // e不可以省略 this.count -= step; } } }) </script> </body>
Copied!
# 11.11.2 v-on事件修饰符
事件修饰符表格:
修饰符 | 描述 |
---|---|
.stop | 阻止事件冒泡(调用 event.stopPropagation()) |
.prevent | 阻止默认事件(调用 event.preventDefault()。) |
.capture | 添加事件捕获 |
.self | 只能由自身触发事件 |
.once | 该事件只会触发一次 |
<body> <div id="root"> <!-- .stop --> <div @click="stopWai"> <div @click.stop="stopNei">哈哈</div> </div> <!-- .prevent --> <a href="http://www.baidu.com">去百度</a> <a href.prevent="http://www.baidu.com">你哪那也去不了</a> <!-- .capture --> <div @click="stopWai"> <div @click.capture="stopNei"> <div @click="stopChange">哈哈哈</div> </div> </div> <!-- .self --> <div @click="stopWai"> 外面 <div @click.self="stopNei"> 中间 <div @click="stopChange">里面</div> </div> </div> <!-- .once --> <button @click.once="stopChange">点击</button> </div> <!-- native .passive --> <script> var vm = new Vue({ el: "#root", data: { msg:'我出现了' }, methods: { stopWai(){ console.log('我是外部出现的'); }, stopNei(){ console.log('我是内部出现的'); }, stopChange(){ console.log('中心出现的'); } }, }) </script> </body>
Copied!
# 11.11.3 v-on按键修饰符
<body> <div id="root"> <!-- 键盘按键 = 键值 --> <input v-on:keyup.13='submit'> <input v-on:keyup.enter='submit'> </div> <script> var vm = new Vue({ el: "#root", data: { msg:'我出现了' }, methods: { submit(){ console.log('我被回车了') } } }) </script> </body>
Copied!
按键修饰符表格:
修饰符 | 描述 |
---|---|
.enter | 回车 |
.tab | tab键 |
.delete | 删除”和“退格 |
.esc | 退出 |
.space | 空格 |
.up | ↑ |
.down | ↓ |
.left | ← |
.right | → |
# 11.12 自定义指令
# 11.12.1 基本用法
- 全局: Vue.directive(名字, function(el, binding, vnode){...})
- 局部: detectives: {'名字': function(el, binding, vnode){...}}
<body> <div id="root"> <!-- 小写转大 全局--> <!-- v-text v-html {{}} --> <h1 v-upper*text='msgMax'></h1> <!-- 大转小 局部 --> <h1 v-lower-text='msgMin'></h1> </div> <script> //定义全局指令 Vue.directive('upper*text',function(el,binding){ console.log(el,binding) el.innerHTML=binding.value.toUpperCase() }) var vm = new Vue({ el: "#root", data: { msgMax:'i love you', msgMin:'HELLO WORLD' }, //局部定义 directives:{ 'lower-text':function(el,binding){ el.innerHTML=binding.value.toLowerCase() }} }) </script> </body>
Copied!
# 11.12.2 钩子函数
函数 | 描述 |
---|---|
bind | 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。 |
inserted | 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 |
update | 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 。 |
componentUpdated | 指令所在组件的 VNode 及其子 VNode 全部更新后调用。 |
unbind | 只调用一次,指令与元素解绑时调用。 |
# 11.12.3 钩子函数的参数
函数 | 描述 |
---|---|
el | 指令所绑定的元素,可以用来直接操作 DOM。 |
binding | 一个对象,包含一下这些属性(name、value、oldValue、expression、arg、modifiers) |
vnode | vue 编译生成的虚拟节点。 |
oldnode | 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。 |
TIP
- 当指令第一次被绑定到元素上的时候,会立即触发bind 函数
- 形参中的el表示当前指令所绑定到的那个DOM对象
- 页面DOM更新时会调用update函数
# 11.12.4 指令简写
<template> <div id="app"> <h1 v-color="color">这是根组件</h1> <button @click="color='green'">改变文字颜色</button> </div> </template> directives: { color: { bind(el,binding){ el.style.color = binding.value; }, update(el,binding){ el.style.color = binding.value; } } // 函数简写,当bind和update函数相同时 color(el,binding){ el.style.color = binding.value; } }
Copied!
# 11.13 filter过滤器
过滤器(Filters) 是vue为开发者提供的功能,常用于文本的格式化。过滤器可以用在两个地方:插值表达式和v-bind属性绑定。过滤器应该被添加在JavaScript表达式的尾部,由“ 管道符"|
进行调用。
具体用法和指令detective一样,分为局部过滤器和全局过滤器。局部过滤器是使用filters:{}
,全局过滤器是使用Vue.filter(...)
,当局部过滤器与全局过滤器重名冲突时,局部优先。
版本变迁
filter只在vue2提供,vue3不支持filter操作。
# 11.13.1 局部过滤器
<body> <div id="root"> <!-- ¥200 |管道符 --> <h1>苹果的价格:{{price | addPriceIcon}}</h1> <h1>香蕉的价格:{{price1 | addPriceIcon}}</h1> <h1>西瓜的价格:{{price2 | addPriceIcon}}</h1> <h1>葡萄的价格:{{price3 | addPriceIcon}}</h1> <h1>玉米的价格:{{price4 | addPriceIcon}}</h1> </div> <script> var vm = new Vue({ el: "#root", data: { price:200, price1:3000, price2:3050, price3:3400, price4:6000, }, // 局部定义 filters:{ // 过滤器函数形参中的value, 永远都是”|“前面的那个值 addPriceIcon(value){ console.log(value); return '¥' + value + '元' } } }) </script> </body>
Copied!
# 11.13.2 全局过滤器
<body> <div id="root"> <h1>{{viewContent | addName}}</h1> </div> <script> // 定义全局 Vue.filter("addName",(value)=>{ return "今天的天气是:" + value }) var vm = new Vue({ el: "#root", data: { viewContent:'晴天' } }) </script> </body>
Copied!
# 11.13.3 过滤器实现首字母大写
<body> <div id="root"> <!-- 把输入的英文首字母大写 hello world --> <input type="text" v-model="content" @change="changeEvent"> {{viewContent | changeContent}} </div> <script> var vm = new Vue({ el: "#root", data: { content:'', viewContent:'' }, methods: { changeEvent(){ this.viewContent = this.content } }, // 局部定义 filters:{ changeContent(value){ if(value){ let str = value.toString(); let newArr = str.split(" ").map(ele=>{ return ele.charAt(0).toUpperCase() + ele.slice(1) }); return newArr.join(" ") } } } }) </script> </body>
Copied!
版本变迁
vue3已经删除了filter但是Vue2还保留着。
# 11.14 计算属性
computed
: 计算属性
data: { r: 0, g: 0, b: 0 } computed: { rgb(){ return `rgb(${this.r},${this.g},${this.b})` } }
Copied!
- 特点:
- 定义的时候,要被定义为**“方法"格式**
- 在使用计算属性的时候,当普通的属性使用即可,因为已经被挂载在Vue对象上了,可打印查看
- 好处:
- 实现了代码的复用
- 只要计算属性中依赖的数据源变化了,则计算属性会自动重新求值
# 11.15 监听器
watch
: 监听数据变化
# 11.15.1 基本用法
data: { username: 'admin' } watch: { username(newValue,oldValue){ ...... } }
Copied!
# 11.15.2 监听器immediate的用法
- immediate: 进入页面是否触发,true表示自动触发一次
watch: { username: { handler(newValue,oldValue){ ...... }, immediate: true } }
Copied!
# 11.15.3 监听器deep深度监听
data: { info: { username: 'admin' } }, watch: { info: { handler(newValue,oldValue){ ...... }, // 只要对象中任一个属性发生变化,都会触发对象的监听器 deep: true } }
Copied!
# 11.15.4 监听对象里的某一个属性的变化
data: { info: { username: 'admin' } }, watch: { 'info.username'(newValue,oldValue){ ...... } }
Copied!
# 12. axios
TIP
axios是一个专注于网络请求的库
axios({ method:'请求的类型', url:'请求的URL地址', params: {}, data: {} }).then((result) => { // .then 用来指定请求成功之后的回调函数 // 形参中的result 是请求成功之后的结果 }
Copied!
axios的使用
- GET用params
- POST用data
- await - async
document.querySelector('#btnPost').addEventListener('click',async function(){ //如果调用某个方法的返回值是Promise 实例,则前面可以添加await // await只能用在被async “修饰”的方法中 const { data } = await axios({ method: 'POST', url: 'http://www.liulongbin.top:3006/api/post', data: { name :'zs', age: 20 } }) })
Copied!
document.querySelector('#btnGet').addEventListener('click',async function(){ //解构赋值的时候使用:进行重命名 const {data: res} = await axios({ method: 'GET' , url: 'http://www.liulongbin.top:3006/api/getbooks' }) console.log(res.data) })
Copied!
# 12.1 axios的get方法
document.querySelector('#btnGET').addEventListener('click',async function(){ const {data: res} = await axios.get('http://www.liulongbin.top:3006/api/getbooks',{ params:{ id: 1 } }) console.log(res) })
Copied!
# 12.2 axios的post方法
document.querySelector('#btnGET').addEventListener('click',async function(){ const {data: res} = await axios.post('http://www.liulongbin.top:3006/api/getbooks',{ name: 'zs', age: 20 }) console.log(res) })
Copied!
# 12.3 把axios挂载到Vue到原型上
- 在main.js文件中写入,这样每个文件都能访问
import axios from 'axios' // 配之后就不用每次都写完整的路径 axios.defaults.baseURL = 'XXXXXX' Vue.prototype.$http = axios
Copied!
- 使用axios
this.$http('/api/post',{ name: 'zs',age: 20 })
Copied!
← 前端笔记