Vue 基础快速入门(一)
Vue
渐进式 JavaScript 框架,用来动态构建用户界面
特点:
- 遵循 MVVM 模式
- 编码简洁,体积小,运行效率高,适合 移动/PC 端开发
- 它本身只关注 UI,可以轻松引入 vue 插件或其它第三方库开发项目
- 采用组件化模式,提高代码复用率、且让代码更好维护
- 声明式编码,让编码人员无需直接操作 DOM,提高开发效率
- 使用虚拟 DOM 和 Diff 算法,尽量复用 DOM节点
借鉴 angular 的 模板 和 数据绑定 技术
借鉴 react 的 组件化 和 虚拟DOM 技术
引入 Vue
本地引入
CDN 引入
快速创建 Vue 的实例
概念性的问题:
- 想让 Vue 工作,就必须创建一个Vue实例,且要传入一个配置对象
- root 容器里的代码被称为 Vue 模板
- Vue 实例和容器是一一对应的
- 真实开发中只有一个 Vue 实例,并且会配合着组件一起使用
el: 又称挂载点,可认为是 element 的简写,创建一个 vue实例 得知道是在哪一块元素上创建 Vue实例 ,对哪一块视图进行操作
var vm = new Vue({el: '#root',data: {msg: '123'},methods: {test() { }}
})
el 和 data 的两种写法
data 与 el 的2种写法
- el 有2种写法
(1) new Vue 时候配置 el 属性
(2) 先创建 Vue 实例,随后再通过 vm.$mount(’#root’) 指定 el 的值 - data 有2种写法
(1) 对象式
(2) 函数式
如何选择: 目前哪种写法都可以,以后学习到组件时,data 必须使用函数式,否则会报错 - 一个重要的原则:
由 Vue 管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是 Vue 实例了
Vue 管理的函数举例:data(), method方法中定义的函数等
Vue 的插值语法
{{js 表达式}} 用于解析标签体内容
<div id="test"><input type="text" v-model="msg"><br><!--调用函数--><p>Hello {{msg.toUpperCase()}} </p>
</div><script src="CDN 引入或者本地引入vue.js"></script>
<script>const vm = new Vue({ // 配置对象 options // 配置选项(option)el: '#test', // element: 指定用vue来管理页面中的哪个标签区域data: { // 数据(model)msg: 'World'}})
</script>
理解 MVVM
M: 模型(Model) :data中的数据
V: 视图(View) :模板代码 (不是静态页面) (两个语法:指令,大括号表达式)
VM: viewModel: 视图模型 (Vue的实例)
- Dom Listeners (Dom 监听)
- Data Bindings (数据绑定)
MVVM 本质上是 MVC (Model-View- Controller)的改进版。即模型-视图-视图模型。
模型 model 指的是后端传递的数据,视图 view 指的是所看到的页面。
视图模型 viewModel 是 mvvm 模式的核心,它是连接 view 和 model 的桥梁。它有两个方向:
将模型转化成视图,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定
将视图转化成模型,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听
这两个方向都实现的,我们称之为数据的双向绑定
- data 中所有的属性,最后都出现在了 vm 身上。
- vm 身上所有的属性 及 Vue 原型上所有属性,在 Vue 模板中都可以直接使用
理解模板
- 动态 html 页面
- 包含了 js 代码
插值语法: {{xxx}} 用于解析标签体的内容, 可以向页面输出数据
指令语法: v- 开头的自定义标签属性
数据绑定
v-bind: 数据绑定 (指定变化的属性值)
v-bind:xxx='yy' // yy 会被作为表达式解析
// 简写
:xxx='yy'
特点: 数据只能从 data 流向页面, 是单向数据绑定
v-model: 双向的数据绑定
数据能从 data 流向页面, 还能从页面流向 data
只能应用于表单类元素 (输入类元素) 上
收集表单数据:
若:<input type="text"/>,则v-model默认收集的是value值,用户输入的就是value值。
若:<input type="password"/>,则v-model默认收集的是value值,用户输入的就是value值。
若:<input type="radio"/>,则v-model默认收集的是value值,因为此类型无法输入内容,则无法通过输入得到value值,所以要给标签手动添加value值。
若:<input type="checkbox"/>1.没有配置input的value属性,那么默认读取的的就是checked是否被勾选(勾选 or 未勾选,是布尔值)2.配置input的value属性:(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)(2)v-model的初始值是数组,那么收集的的就是value组成的数组
v-model 的三个修饰符
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
v-model:value='yy'
// 简写 因为 v-model 默认收集的就是 value 值
v-model='yy'
v-text: 向所在节点渲染文本内容
和插值语法的区别: v-text 会替换节点的内容, 插值语法不会
v-html: 像节点中渲染包含 html 结构的内容
和插值语法的区别:
- v-html 会替换节点所有内容, 插值语法不会
- v-html 可以识别 html 结构
- 注意: v-html 有安全性问题, 在网站动态渲染任意 html 是非常危险的, 容易遭受 XSS 攻击, 要在可信的内容使用 v-html, 不要使用在用户提交的内容上
<body><div id='app'><h2>1. 大括号表达式</h2><p>{{msg}}</p> <!--textContent --><p>{{msg.toUpperCase()}}</p><p v-html="msg"></p> <!--innerHTML --><p v-text="msg"></p> <!--textContent --><p v-text="msg.toUpperCase()"></p><h2>2. 指令一: 强制数据绑定</h2><img src="imgUrl" alt="Vue"> <!--无法显示图片,没有识别成js表达式 --><img v-bind:src="imgUrl" alt="Vue"> <!--属性值识别成js表达式 --><img :src="imgUrl" alt="Vue"><h2>3. 指令二: 绑定事件监听</h2><button v-on:click="test1">test1</button><button @click="test1">test1</button><button @click="test2('abc')">test2</button> <!--可以传参数 --><button @click="test2(msg)">test2</button></div><script src="../js/vue.js"></script><script>new Vue({el: '#app',data: {msg: '<a href="http:www.baidu.com">I Will Back!</a>',imgUrl: "https://cn.vuejs.org/images/logo.png"},methods: {test1() {alert('heheh');},test2(content){alert(content);}}})</script>
</body>
Object.defineProperty()
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>回顾Object.defineproperty方法</title></head><body><script type="text/javascript">let number = 18let person = {name: '张三',sex: '男',}//Object.defineProperty给对象添加属性Object.defineProperty(person, 'age', {//里面三个参数(对象,属性名,options配置对象{})// value: 18,// enumerable: true, //控制属性是否可以枚举(遍历),默认值是false// writable:true, //控制属性是否可以被修改,默认值是false// configurable:true //控制属性是否可以被删除,默认值是false//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值get() {console.log('有人读取age属性了')return number},//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值set(value) {console.log('有人修改了age属性,且值是', value)number = value}})// console.log(Object.keys(person))console.log(person)</script></body>
</html>
事件
v-on: 绑定事件监听
绑定指定事件名的回调函数
v-on:click='xxx'
v-on:keyup='xxx(参数)'
v-on:keyup.enter='xxx'
// 简写
@click='xxx'
@keyup='xxx'
@keyup.enter='xxx'
事件修饰符
- prevent:阻止默认事件
- stop:阻止事件冒泡
- once:事件只触发一次
- capture:使用事件的捕获模式
- self:只有event.target是当前操作的元素时才触发事件
- passive:事件的默认行为立即执行,无需等待事件回调执行完毕
键盘事件
Vue 中常用的按键别名:
回车 => enter
删除 => delete (捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab (特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right
系统修饰键(用法特殊):tab、ctrl、alt、shift、meta(win)
(1) 配合 keyup 使用: 按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
(2) 配合 keydown 使用: 正常触发事件
<div id="root"> <h2>欢迎来到{{name}}学习</h2><input type="text" placeholder="输入" @keydown.huiche="showInfo"><!-- <input type="text" placeholder="提示输入" @keydown.enter="showInfo"> --><!--当有需求要同时按下两个键才能生效时 <input type="text" placeholder="提示输入" @keyup.ctrl.y="showInfo"> -->
</div>
计算属性
只要 data 中的数据发生改变, Vue 会重新解析模板
- 在 computed 属性对象中定义计算属性的方法
- 在页面中使用
{{方法名}}
来显示计算的结果
原理:底层借助了 Objcet.defineproperty
方法提供的 getter
和 setter
get 函数什么时候执行?
(1) 初次读取时会执行一次。
(2) 当依赖的数据发生改变时会被再次调用。
优势:与 methods 实现相比,内部有缓存机制, 效率更高,调试方便。
备注:
- 计算属性最终会出现在vm上,直接读取使用即可。
- 如果计算属性要被修改,那必须写 set 函数去响应修改,且 set 中要引起计算时依赖的数据发生改变
//完整写法fullName:{get(){console.log('get被调用了')return this.firstName + '-' + this.lastName},set(value){console.log('set',value)const arr = value.split('-')this.firstName = arr[0]this.lastName = arr[1]}
}
简写 (只读不改就可以用简写)
//简写
fullName(){console.log('get被调用了')return this.firstName + '-' + this.lastName
}
监视属性
通过 vm 的 $watch() 或 watch 配置来监视指定的属性 (可以监视计算属性中的属性)
属性变化时, 回调函数自动调用, 在函数内部进行计算
监视的属性必须存在,才能进行监视
两种写法:
new Vue 时传入 watch 配置
watch: {isHot: {immediate: true, //初始化时让 handler 调用一下//当 isHot 发生改变时, 调用 handlerhandler(newValue, oldValue){console.log('isHot被修改了',newValue,oldValue)}} }
通过 vm.$watch 监视
vm.$watch('isHot',{immediate: true, //初始化时让 handler 调用一下handler(newValue,oldValue){console.log('isHot被修改了',newValue,oldValue)} })
深度监视
监视某个 number 的 a 属性
'numbers.a':{deep:true,handler(){console.log('numbers改变了')}
}
(1) Vue 中的 watch 默认不监测对象内部值的改变 (一层)
(2) 配置 deep:true 可以监测对象内部值改变 (多层)
备注:
(1) Vue 自身可以监测对象内部值的改变,但 Vue 提供的 watch 默认不可以!
(2) 使用 watch 时根据数据的具体结构,决定是否采用深度监视
numbers:{deep:true,handler(){console.log('numbers改变了')}
}
一般写法
isHot:{// immediate:true, //初始化时让 handler 调用一下// deep:true,//深度监视handler(newValue,oldValue){console.log('isHot被修改了',newValue,oldValue)}
}
简写
//简写
isHot(newValue,oldValue){console.log('isHot被修改了',newValue,oldValue,this)
}
计算属性和监视属性的区别
- computed 能完成的功能,watch 都可以完成
- watch 能完成的功能,computed 不一定能完成,例如: watch 可以进行异步操作
重要原则
- 所被 Vue 管理的函数,最好写成普通函数,这样 this 的指向才是 vm 或 组件实例对象
- 所有不被 Vue 所管理的函数 (定时器的回调函数、ajax 的回调函数等、Promise 的回调函数), 最好写成箭头函数,这样 this 的指向才是 vm 或组件实例对象
样例代码
<body><div id="demo">姓:<input type="text" placeholder="First Name" v-model="firstName"><br>名:<input type="text" placeholder="Last Name" v-model="lastName"><br>姓名1(单向):<input type="text" placeholder="Full Name1" v-model="fullName1"><br>姓名2(单向):<input type="text" placeholder="Full Name2" v-model="fullName2"><br>姓名3(双向):<input type="text" placeholder="Full Name3" v-model="fullName3"><br><p>{{fullName1}}</p><p>{{fullName1}}</p><p>{{fullName1}}</p></div><script src="../js/vue.js"></script><script>const vm = new Vue({el: '#demo',data: {firstName: 'A',lastName: 'B',fullName2: 'A B'},computed: {// 什么时候执行:初始化显示 / 相关的data属性数据发生改变// 做什么的: 计算并返回当前属性的值fullName1() { //计算属性中的一个方法,方法的返回值作为属性 (回调函数)console.log('fullName1()') // 必然会掉用return this.firstName + ' ' + this.lastName;},fullName3: { //不是函数是一个对象,里面有两个方法 get() {// 回调函数 : 1. 你定义的 2. 你没有调用 3. 但他最终执行了// 1. 什么时候调用? 2. 用来做什么// 回调函数 当需要读取当前属性值时回调 根据相关的数据计算并返回当前属性的值return this.firstName + ' ' + this.lastName;},set(value) {// 回调函数 监视当前属性值的变化 当属性值发生改变时回调 更新相关的属性数据const names = value.split(' ');this.firstName = names[0];this.lastName = names[1];}}},watch: { //配置监视firstName: function(value){ // firstName 发生了变化console.log(this); //就是vm对象this.fullName2 = value + ' ' + this.lastName;}}});vm.$watch('lastName', function(value) {//更新fullName2this.fullName2 = this.firstName + ' ' + value;})</script>
绑定样式
1. class 样式
写法 :class="xxx" xxx可以是字符串、对象、数组。
字符串写法适用于:类名不确定,要动态获取。
数组写法适用于:要绑定多个样式,个数不确定,名字也不确定。
对象写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
2. style 样式
:style="{fontSize: xxx}"其中xxx是动态值。:style="[a,b]"其中a、b是样式对象。
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>绑定样式</title><style>.basic {width: 400px;height: 100px;border: 1px solid black;}.happy {border: 4px solid red;;background-color: rgba(255, 255, 0, 0.644);background: linear-gradient(30deg, yellow, pink, orange, yellow);}.sad {border: 4px dashed rgb(2, 197, 2);background-color: gray;}.normal {background-color: skyblue;}.atguigu1 {background-color: yellowgreen;}.atguigu2 {font-size: 30px;text-shadow: 2px 2px 10px red;}.atguigu3 {border-radius: 20px;}</style><script type="text/javascript" src="../js/vue.js"></script></head><body><!-- 准备好一个容器--><div id="root"><!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 --><div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br /><br /><!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 --><div class="basic" :class="classArr">{{name}}</div> <br /><br /><!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 --><div class="basic" :class="classObj">{{name}}</div> <br /><br /><!-- 绑定style样式--对象写法 --><div class="basic" :style="styleObj">{{name}}</div> <br /><br /><!-- 绑定style样式--数组写法 --><div class="basic" :style="styleArr">{{name}}</div></div></body><script type="text/javascript">Vue.config.productionTip = falseconst vm = new Vue({el: '#root',data: {name: '我要进大厂',mood: 'normal',classArr: ['atguigu1', 'atguigu2', 'atguigu3'],classObj: {atguigu1: true,atguigu2: false,},styleObj: {fontSize: '40px',color: 'red',},styleObj2: {backgroundColor: 'orange'},styleArr: [{fontSize: '40px',color: 'blue',},{backgroundColor: 'gray'}]},methods: {changeMood() {//随机切换心情const arr = ['happy', 'sad', 'normal']const index = Math.floor(Math.random() * 3)//Math.random() 返回 0 ~ 1 之间的随机数,包含 0 不包含 1。//Math.floor(x) 对 x 进行下舍入,即向下取整。this.mood = arr[index]}},})</script>
</html>
条件渲染
v-if
v-else-if
v-else
适用于: 切换频率较低的场景
特点: 不展示的 DOM 元素直接被移除
v-show
适用于: 切换频率较高的场景。
特点: 不展示的 DOM 元素未被移除,仅仅是使用样式隐藏掉
注: v-if 的时候,元素可能无法获取到,而使用 v-show 一定可以获取到
比较 v-if 和 v-show
- 如果需要频繁切换 v-show 较好
- 当条件不成立时, v-if 的所有子节点不会解析
// v-if 和 template 配合使用
<template v-if="n === 1"><h2>hi</h2><h2>hi</h2>
</template>
列表渲染
v-for
- 用于展示列表数据
- 可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
v-for
指令需要使用item in items
形式的特殊语法,其中items
是源数据数组,而item
则是被迭代的数组元素的别名(形参)v-for
还支持一个可选的第二个参数,即当前项的索引。- 语法:v-for="(item, index) in xxx" :key=“yyy”
- 你也可以用
of
替代in
作为分隔符,因为它更接近 JavaScript 迭代器的语法
key 的原理
有相同父元素的子元素必须有独特的 key, 重复的 key 会造成渲染错误
react、vue中的key有什么作用? (key的内部原理)
虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:对比规则:
(1) 旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:
①.若虚拟 DOM 中内容没变, 直接使用之前的真实 DOM!
②.若虚拟 DOM 中内容变了, 则生成新的真实 DOM,随后替换掉页面中之前的真实 DOM。
(2) 旧虚拟 DOM 中未找到与新虚拟DOM相同的key创建新的真实 DOM,随后渲染到到页面。用 index 作为 key 可能会引发的问题:
1.若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实 DOM 更新 ==> 界面效果没问题, 但效率低。2.如果结构中还包含输入类的 DOM: 会产生错误 DOM 更新 ==> 界面有问题。
开发中如何选择 key?
1.最好使用每条数据的唯一标识作为 key, 比如 id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用 index 作为 key 是没有问题的。
3.如果不写 key,则默认为 index
列表过滤
用 computed 实现 (推荐)
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>列表过滤</title><script type="text/javascript" src="../js/vue.js"></script></head><body><!-- 1.收集用户输入
2.拿用户输入的东西进行数据匹配
--><!-- 准备好一个容器--><div id="root"><h2>人员列表</h2><input type="text" placeholder="请输入名字" v-model="keyWord"><ul><li v-for="(p,index) of filPerons" :key="index">{{p.name}}-{{p.age}}-{{p.sex}}</li></ul></div><script type="text/javascript">Vue.config.productionTip = false// 用 computed 实现new Vue({el: '#root',data: {keyWord: '',persons: [{ id: '001', name: '马冬梅', age: 19, sex: '女' },{ id: '002', name: '周冬雨', age: 20, sex: '女' },{ id: '003', name: '周杰伦', age: 21, sex: '男' },{ id: '004', name: '温兆伦', age: 22, sex: '男' }]},computed: {filPerons() {return this.persons.filter((p) => {return p.name.indexOf(this.keyWord) !== -1})}}})</script></html>
用 watch 实现
//将下面代码放入上方代码块中
new Vue({el: '#root',data: {keyWord: '',persons: [{ id: '001', name: '马冬梅', age: 19, sex: '女' },{ id: '002', name: '周冬雨', age: 20, sex: '女' },{ id: '003', name: '周杰伦', age: 21, sex: '男' },{ id: '004', name: '温兆伦', age: 22, sex: '男' }],filPerons: []},watch: {keyWord: {immediate: true,// 初始化的时候让handler调用一下,因为开始filPerons: []为空数组,// 页面上什么内容都不显示,而恰巧handler(val)获取的值为空,// 而所有字符串第0位不仅包含自己第一个字符,也包含着一个空字符,p.name.indexOf('')为0 // 所以handler(val)函数判断成功,页面显示内容handler(val) {this.filPerons = this.persons.filter((p) => {return p.name.indexOf(val) !== -1// 判断p.name中是否包含有val值,如果不等于-1,则说明包含// filter返回一个全新的数组,原数组不变})}}}
})
列表排序
列表排序与列表过滤一般是连在一起使用的
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>列表排序</title><script type="text/javascript" src="../js/vue.js"></script></head><body><!-- 准备好一个容器--><div id="root"><h2>人员列表</h2><input type="text" placeholder="请输入名字" v-model="keyWord"><button @click="sortType = 2">年龄升序</button><button @click="sortType = 1">年龄降序</button><button @click="sortType = 0">原顺序</button><ul><li v-for="(p,index) of filPerons" :key="p.id">{{p.name}}-{{p.age}}-{{p.sex}}<input type="text"></li></ul></div><script type="text/javascript">Vue.config.productionTip = falsenew Vue({el: '#root',data: {keyWord: '',sortType: 0, //0原顺序 1降序 2升序persons: [{ id: '001', name: '马冬梅', age: 30, sex: '女' },{ id: '002', name: '周冬雨', age: 31, sex: '女' },{ id: '003', name: '周杰伦', age: 18, sex: '男' },{ id: '004', name: '温兆伦', age: 19, sex: '男' }]},computed: {filPerons() {const arr = this.persons.filter((p) => {return p.name.indexOf(this.keyWord) !== -1})//判断一下是否需要排序if (this.sortType !== 0) {arr.sort((p1, p2) => {return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age})}return arr}}})</script></html>
监视数据原理
更新时的问题
为什么 this.person[0] = {id:'001', name:'马老师', age:50, sex:'男'}
Vue 没有检测到改变 ?
Vue监视数据的原理:
- vue 会监视 data 中所有层次的数据。
- 如何监测对象中的数据?
通过 setter 实现监视,且要在 new Vue 时就传入要监测的数据。
(1) 对象中后追加的属性,Vue 默认不做响应式处理,即改变其值页面无变化
(2) 如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或
vm.$set(target,propertyName/index,value)
// vm.$set(添加目标,‘添加属性/索引值’,‘属性值’) - 如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1) 调用原生对应的方法对数组进行更新
(2) 重新解析模板,进而更新页面 - 在 Vue 修改数组中的某个元素一定要用如下方法:
1.使用这些API: push()、pop()、shift() (删除第一个)、unshift()、splice() (删除, 替换, 插入 指定位置元素)、sort()、reverse()
2.Vue.set() 或 vm.$set()
3.如果不使用上面方法而是直接对数组赋值则 vue 无法响应,例如:
this.student.hobby[0] = “开车”,数据已被更改,但页面中无任何反应
特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象(vm._data) 添加属性
对于 filter 如何让 Vue 监测? 直接把过滤后的数组直接传给原数组
array.splice(index, howmany, item1, ....., itemX)
// index 必须, 整数,指定在什么位置添加/删除项目,使用负值指定从数组末尾开始的位置
// howmany 可选, 要删除的项目数, 如果设置为 0,则不会删除任何项目
// 可选, 要添加到数组中的新项目
过滤器
对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)
语法:
- 注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
- 使用过滤器:{{ xxx | 过滤器名 }} 或 v-bind:属性 = “xxx | 过滤器名”
备注:
- 过滤器也可以接收额外参数、多个过滤器也可以串联
- 并没有改变原本的数据, 是产生新的对应的数据
- 不是必须的属性,完全可以用 methods 和 computed 实现下面代码中的过滤功能
- 当全局过滤器和局部过滤器重名时,会采用局部过滤器
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>过滤器</title><script type="text/javascript" src="../js/vue.js"></script><!-- <script type="text/javascript" src="../js/dayjs.min.js"></script> --><script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js"></script></head><body><!-- 准备好一个容器--><div id="root"><h2>显示格式化后的时间</h2><!-- 计算属性实现 --><h3>计算属性实现:{{fmtTime}}</h3><!-- methods实现 --><h3>methods实现:{{getFmtTime()}}</h3><!-- 过滤器实现 --><h3>过滤器实现:{{time | timeFormater}}</h3> //将time当参数传给timeFormater<!-- 过滤器实现(传参) --><h3>过滤器实现(传参):{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3><h3 :x="msg | mySlice">{{msg}}</h3></div><div id="root2"><h2>{{msg | mySlice}}</h2></div></body><script type="text/javascript">Vue.config.productionTip = false//全局过滤器,必须在new Vue({})之前Vue.filter('mySlice', function (value) {return value.slice(0, 4)})new Vue({el: '#root',data: {time: 1621561377603, //时间戳msg: '你好,尚硅谷'},computed: {fmtTime() {return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')}},methods: {getFmtTime() {return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')}},// filters: {// timeFormater(value) {// return dayjs(value).format('YYYY年MM月DD日 HH:mm:ss')// }// }//局部过滤器filters: {//如果不传参数,则使用默认参数'YYYY年MM月DD日 HH:mm:ss',如果传参数,则使用//传入的参数'YYYY_MM_DD'timeFormater(value, str = 'YYYY年MM月DD日 HH:mm:ss') {// console.log('@',value)return dayjs(value).format(str)}}})new Vue({el: '#root2',data: {msg: 'hello,atguigu!'}})</script>
</html>
常用指令
v-cloak 指令
- 本质是一个特殊属性,Vue 实例创建完毕并接管容器后,会删掉 v-cloak 属性
- 使用 css 配合 v-cloak 可以解决网速慢时页面展示出模板 {{xxx}} 的问题
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>v-cloak指令</title><style>[v-cloak] {display: none;}</style><!-- 引入Vue --></head><body><div id="root"><h2 v-cloak>{{name}}</h2></div><script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script></body><script type="text/javascript">new Vue({el: '#root',data: {name: '尚硅谷'}})</script>
</html>
v-once
- v-once 所在节点在初次动态渲染后,就视为静态内容了
- 以后数据的改变不会引起 v-once 所在结构的更新,可以用于优化性能
<div id="root"><h2 v-once>初始化的n值是:{{n}}</h2><h2>当前的n值是:{{n}}</h2><button @click="n++">点我n+1</button>
</div>
v-pre
用于vue性能优化
- 跳过其所在节点的编译过程
- 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译
<div id="root"><h2 v-pre>Vue其实很简单</h2><h2 >当前的n值是:{{n}}</h2><button @click="n++">点我n+1</button>
</div>
自定义指令
需求1:定义一个 v-big 指令,和 v-text 功能类似,但会把绑定的数值放大 10 倍
需求2:定义一个 v-fbind 指令,和 v-bind 功能类似,但可以让其所绑定的 input 元素默认获取焦点
语法:
// 局部指令
new Vue({directives: {指令名: 配置对象}
})
new Vue({directives: {指令名: 回调函数}
})
// 全局指令
Vue.directive(指令名, 配置对象)
Vue.directive(指令名, 回调函数)
二、配置对象中常用的3个回调:
(1) bind: 指令与元素成功绑定时调用。
(2) inserted: 指令所在元素被插入页面时调用。
(3) update: 指令所在模板结构被重新解析时调用。
三、备注:
1. 指令定义时不加 v-,但使用时要加 v-
2. 指令名如果是多个单词,要使用 kebab-case 命名方式,别忘了加"", 不要用 camelCase 命名
3. 所有指令相关的 this 都是 window
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>自定义指令</title><script type="text/javascript" src="../js/vue.js"></script></head><body><!-- 准备好一个容器--><div id="root"><h2>{{name}}</h2><h2>当前的n值是:<span v-text="n"></span> </h2><!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> --><h2>放大10倍后的n值是:<span v-big="n"></span> </h2><button @click="n++">点我n+1</button><hr /><input type="text" v-fbind:value="n"></div></body><script type="text/javascript">Vue.config.productionTip = false//定义全局指令/* Vue.directive('fbind',{//指令与元素成功绑定时(一上来)bind(element,binding){element.value = binding.value},//指令所在元素被插入页面时inserted(element,binding){element.focus()},//指令所在的模板被重新解析时update(element,binding){element.value = binding.value}})Vue.directive('big',function(element, binding) { //两个参数:当前DOM元素(span),本次绑定的所有信息console.log(element, binding)// console.log('big', this) //注意此处的this是windowelement.innerText = binding.value * 10},)*/new Vue({el: '#root',data: {name: '尚硅谷',n: 1},directives: {//指令名如果是多个单词,别忘了加"",方法内部放的是"key",value值,大部分情况""可省略,但加了-之后引号必须带。// 全写是: 'big-number':function(element,binding){} /* 'big-number'(element,binding){// console.log('big')element.innerText = binding.value * 10}, */// big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。big(element, binding) { //两个参数:当前DOM元素(span),本次绑定的所有信息console.log(element, binding)// console.log('big', this) //注意此处的this是windowelement.innerText = binding.value * 10},fbind: {//指令与元素成功绑定时(一上来)调用bind(element, binding) {//两个参数:当前DOM元素(input),本次绑定的所有信息element.value = binding.value},//指令所在元素被插入页面时调用inserted(element, binding) {element.focus()// input输入框自动获取焦点,这句代码必须放在将input放入页面的后面},//指令所在的模板被重新解析时调用update(element, binding) {element.value = binding.valueelement.focus()}}}})</script>
</html>
生命周期
- 又叫做生命周期回调函数、生命周期函数、生命周期钩子
- 是 Vue 在关键时刻帮我们调用的一些特殊名称的函数
- 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
- 生命周期函数中的 this 指向是 vm 或 组件实例对象, 这意味着你不能使用箭头函数来定义一个生命周期方法 (例如 created: () => this.fetchTodos())
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>引出生命周期</title><!-- 引入Vue --><script type="text/javascript" src="../js/vue.js"></script></head><body> <div id="root"><h2 :style="{opacity:opacity}">欢迎学习Vue</h2><button @click="opacity = 1">透明度设置为1</button><button @click="stop">点我停止变换</button></div></body><script type="text/javascript">const vm = new Vue({el: '#root',data: {opacity: 1},methods: {stop() {this.$destroy()}},// Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted(挂载),只是初始化的时候调用了一次,后续数据更改重新解析模板时不会再次调用mounted() {console.log('mounted', this)this.timer = setInterval(() => {// 这里箭头函数无this,自动寻找上下文this,找到了mounted()的this,这个this指向vmconsole.log('setInterval')this.opacity -= 0.01if (this.opacity <= 0) this.opacity = 1}, 16)},beforeDestroy() {console.log('vm即将被销毁')clearInterval(this.timer)// 清除定时器},})//通过外部的定时器实现(不推荐)// setInterval(() => {// vm.opacity -= 0.01// if (vm.opacity <= 0) { vm.opacity = 1 }// }, 16)</script>
</html>
生命周期流程
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>分析生命周期</title><!-- 引入Vue --><script type="text/javascript" src="../js/vue.js"></script></head><body><!-- 准备好一个容器--><div id="root" :x="n"><h2 v-text="n"></h2><h2>当前的n值是:{{n}}</h2><button @click="add">点我n+1</button><button @click="bye">点我销毁vm</button></div></body><script type="text/javascript">const vm = new Vue({el: '#root',// template: `// <div>// <h2>当前的n值是:{{n}}</h2>// <button @click="add">点我n+1</button>// </div>// `,//使用template模板,容器内就不用放入内容了,不过template模板解析的时候会将外面的root容器给覆盖掉。// 而且template模板只能有一个根元素,所以必须用div 将h2与button包裹起来,否则报错data: {n: 1},methods: {add() {console.log('add')this.n++},bye() {console.log('bye')this.$destroy()// 调用销毁函数,但之前的工作成果还在,只是以后不能管理了}},watch: {n() {console.log('n变了')}},beforeCreate() { //看图:这里是指数据代理和数据监测创建之前,不是vmconsole.log('beforeCreate')// console.log(this);// debugger// 此时打开控制台可以看到data中无数据,无methods方法},created() {console.log('created')// console.log(this);// debugger// 此时打开控制台可以看到data中有数据,有add,bye方法},beforeMount() {console.log('beforeMount')// console.log(this);// debugger// 元素都加载完成(未经编译),但还没有挂载上去,HTML的body结构里呈现的依然是模板// 在这里面操作DOM白操作,最终会被虚拟dom转换成的真实dom覆盖掉},mounted() {console.log('mounted')// console.log(this);// debugger// 元素都加载完成(编译完成),已经挂载上去了,HTML的body结构里呈现的你想让他呈现的样子// 在这里面操作DOM有效,但不推荐},beforeUpdate() {console.log('beforeUpdate')// console.log(this.n);// debugger// 更新数据时调用,数据为新的,但页面还是旧的,尚未更新},updated() {console.log('updated')// console.log(this.n);// debugger// 数据为新的,但页面也是新的,数据与页面保持同步},beforeDestroy() {console.log('beforeDestroy')// console.log(this.n);// this.add()// debugger//销毁阶段触发// 点击销毁vm,能打印出n,调用了add方法,但页面不再更新,即到了这个阶段,//能够访问到数据,调用方法, 但所有对数据的修改不会再触发更新了。// 此时vm中的data methods 指令等都处于可用状态,马上要执行销毁过程,// 一般在此阶段:关闭定时器,取消订阅消息,解绑自定义事件等收尾操作},destroyed() {//销毁阶段触发console.log('destroyed')},})// vm.$mount("#root")</script>
</html>
常用的生命周期钩子:
1. mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等 (初始化操作)2. beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等 (收尾工作)
关于销毁 Vue 实例
1. 销毁后借助 Vue 开发者工具看不到任何信息。2. 销毁后自定义事件会失效,但原生 DOM 事件依然有效。
3. 一般不会在 beforeDestroy 操作数据,因为即便操作数据,也不会再触发更新流程了
vm的一生(vm的生命周期)∶
将要创建===>调用beforeCreate函数 创建完毕===>调用created函数。
将要挂载===>调用beforeMount函数
(重要)挂载完毕===>调用mounted函数 ============>【重要的钩子】
将要更新===>调用beforeUpdate函数
更新完毕===>调用updated函数
(重要)将要销毁===>调用beforeDestroy函数 ========>【重要的钩子】
销毁完毕===>调用destroyed函数
Vue 基础快速入门(一)相关推荐
- Vue 基础快速入门(二)
Vue 组件化编程 模块, 组件, 模块化与组件化 模块 理解:向外提供特定功能的 js 程序, 一般就是一个 js 文件 为什么:js 文件很多很复杂 作用:复用 js,简化 js 的编写, 提高 ...
- (vue基础试炼_01)使用vue.js 快速入门hello world
文章目录 一.需求案例 二.案例实现 2.1. 原始js写法 2.2. 怎样使用vue.js ? 2.3. 使用vue.js 写法 三.案例vue简述? 四.案例趣味延伸 五.表达值作用及嘱咐语 一. ...
- .NET Core实战项目之CMS 第六章 入门篇-Vue的快速入门及其使用
写在前面 上面文章我给大家介绍了Dapper这个ORM框架的简单使用,大伙会用了嘛!本来今天这篇文章是要讲Vue的快速入门的,原因是想在后面的文章中使用Vue进行这个CMS系统的后台管理界面的实现.但 ...
- Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 4. 函数
什么样的程序员才是优秀的程序员?咪博士认为"慵懒"的程序员才是真正优秀的程序员.听起来不合逻辑?真正优秀的程序员知道如何高效地工作,而不是用不止境的加班来完成工作任务.函数便是程序 ...
- 零基础快速入门web学习路线(含视频教程)
下面小编专门为广大web学习爱好者汇总了一条完整的自学线路:零基础快速入门web学习路线(含视频教程)(绝对纯干货)适合初学者的最新WEB前端学习路线汇总! 在当下来说web前端开发工程师可谓是高福利 ...
- python海龟教程_Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 7. 条件循环...
条件循环能够让程序在条件成立时(即为真时)重复执行循环体中的语句.如果条件一直成立(即永远不会为假),则循环会一直进行下去,不会停止.如果初始时,条件不成立,则循环 1 次也不会执行.Python 中 ...
- 【Python零基础快速入门系列 | 03】AI数据容器底层核心之Python列表
• 这是机器未来的第7篇文章 原文首发地址:https://blog.csdn.net/RobotFutures/article/details/124957520 <Python零基础快速入门 ...
- 【Python零基础快速入门系列 | 07】浪漫的数据容器:成双成对之字典
这是机器未来的第11篇文章 原文首发链接:https://blog.csdn.net/RobotFutures/article/details/125038890 <Python零基础快速入门系 ...
- ROS2零基础快速入门
ROS2入门最快需要多少时间?3天: ROS2开发一款基础机器人需要多久?3个星期: ROS2怎么才能算"精通"?不可能,3年也不行-- 如何判断一款通用性软件成熟并可以投入精力去 ...
最新文章
- NCBI下载SRA数据的4种方法
- 在Tomcat中部署Java Web应用程序几种方式
- nvidia 程序安装失败
- c++原型模式(Prototype)
- linux体验服务器,体验Ubuntu做服务器
- Vue项目如何实现国际化?分享一下基于vue-i18n实现国际化的经验
- LeetCode 1455. 检查单词是否为句中其他单词的前缀
- 论文必备神器,1行代码搞定Latex公式编写,这个4.6M的Python小插件
- 熟悉 CMake(一)
- 分享7个超实用的Emmet(zen coding)HTML代码使用技巧
- android webview 百度地图,Android WebView显示地图
- 解决Solidworks 2016 安装注册Activator.GUI.SSQ卡顿 闪退 崩溃等问题
- 最强卸载工具,彻底卸载无残留IObit Uninstaller 9.0.2.40
- 《Introduction To Modern Cryptography》读书笔记一
- RAdam和LookAhead合二为一
- Arduino基础入门篇25—红外遥控
- 怎么查看自己CSDN博客的具体排名数?
- 【读书笔记】好好思考-成甲
- 算法工程师,上岸了!
- 自动登录XP其实很轻松