Vue

渐进式 JavaScript 框架,用来动态构建用户界面

特点:

  1. 遵循 MVVM 模式
  2. 编码简洁,体积小,运行效率高,适合 移动/PC 端开发
  3. 它本身只关注 UI,可以轻松引入 vue 插件或其它第三方库开发项目
  4. 采用组件化模式,提高代码复用率、且让代码更好维护
  5. 声明式编码,让编码人员无需直接操作 DOM,提高开发效率
  6. 使用虚拟 DOM 和 Diff 算法,尽量复用 DOM节点

借鉴 angular 的 模板数据绑定 技术
借鉴 react 的 组件化虚拟DOM 技术

引入 Vue

本地引入

CDN 引入

快速创建 Vue 的实例

概念性的问题:

  1. 想让 Vue 工作,就必须创建一个Vue实例,且要传入一个配置对象
  2. root 容器里的代码被称为 Vue 模板
  3. Vue 实例和容器是一一对应的
  4. 真实开发中只有一个 Vue 实例,并且会配合着组件一起使用

el: 又称挂载点,可认为是 element 的简写,创建一个 vue实例 得知道是在哪一块元素上创建 Vue实例 ,对哪一块视图进行操作

var vm = new Vue({el: '#root',data: {msg: '123'},methods: {test() {     }}
})

el 和 data 的两种写法

data 与 el 的2种写法

  1. el 有2种写法
    (1) new Vue 时候配置 el 属性
    (2) 先创建 Vue 实例,随后再通过 vm.$mount(’#root’) 指定 el 的值
  2. data 有2种写法
    (1) 对象式
    (2) 函数式
    如何选择: 目前哪种写法都可以,以后学习到组件时,data 必须使用函数式,否则会报错
  3. 一个重要的原则:
    由 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 事件监听

这两个方向都实现的,我们称之为数据的双向绑定


  1. data 中所有的属性,最后都出现在了 vm 身上。
  2. 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 结构的内容

和插值语法的区别:

  1. v-html 会替换节点所有内容, 插值语法不会
  2. v-html 可以识别 html 结构
  3. 注意: 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'

事件修饰符

  1. prevent:阻止默认事件
  2. stop:阻止事件冒泡
  3. once:事件只触发一次
  4. capture:使用事件的捕获模式
  5. self:只有event.target是当前操作的元素时才触发事件
  6. 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 方法提供的 gettersetter

get 函数什么时候执行?
(1) 初次读取时会执行一次。
(2) 当依赖的数据发生改变时会被再次调用。
优势:与 methods 实现相比,内部有缓存机制, 效率更高,调试方便。
备注:

  1. 计算属性最终会出现在vm上,直接读取使用即可。
  2. 如果计算属性要被修改,那必须写 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)
}

计算属性和监视属性的区别

  1. computed 能完成的功能,watch 都可以完成
  2. watch 能完成的功能,computed 不一定能完成,例如: watch 可以进行异步操作

重要原则

  1. 所被 Vue 管理的函数,最好写成普通函数,这样 this 的指向才是 vm 或 组件实例对象
  2. 所有不被 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

  1. 用于展示列表数据
  2. 可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
  3. v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名(形参)
  4. v-for 还支持一个可选的第二个参数,即当前项的索引。
  5. 语法:v-for="(item, index) in xxx" :key=“yyy”
  6. 你也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法

key 的原理

有相同父元素的子元素必须有独特的 key, 重复的 key 会造成渲染错误

react、vue中的key有什么作用? (key的内部原理)

  1. 虚拟DOM中key的作用:
    key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
    随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

  2. 对比规则:
    (1) 旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:
    ①.若虚拟 DOM 中内容没变, 直接使用之前的真实 DOM!
    ②.若虚拟 DOM 中内容变了, 则生成新的真实 DOM,随后替换掉页面中之前的真实 DOM。
    (2) 旧虚拟 DOM 中未找到与新虚拟DOM相同的key创建新的真实 DOM,随后渲染到到页面。

  3. 用 index 作为 key 可能会引发的问题:
    1.若对数据进行:逆序添加、逆序删除等破坏顺序操作:
    会产生没有必要的真实 DOM 更新 ==> 界面效果没问题, 但效率低。

    2.如果结构中还包含输入类的 DOM: 会产生错误 DOM 更新 ==> 界面有问题。

  4. 开发中如何选择 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监视数据的原理:

  1. vue 会监视 data 中所有层次的数据。
  2. 如何监测对象中的数据?
    通过 setter 实现监视,且要在 new Vue 时就传入要监测的数据。
    (1) 对象中后追加的属性,Vue 默认不做响应式处理,即改变其值页面无变化
    (2) 如需给后添加的属性做响应式,请使用如下API:
    Vue.set(target,propertyName/index,value) 或
    vm.$set(target,propertyName/index,value)
    // vm.$set(添加目标,‘添加属性/索引值’,‘属性值’)
  3. 如何监测数组中的数据?
    通过包裹数组更新元素的方法实现,本质就是做了两件事:
    (1) 调用原生对应的方法对数组进行更新
    (2) 重新解析模板,进而更新页面
  4. 在 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,则不会删除任何项目
// 可选, 要添加到数组中的新项目

过滤器

对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)
语法:

  1. 注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
  2. 使用过滤器:{{ xxx | 过滤器名 }} 或 v-bind:属性 = “xxx | 过滤器名”

备注:

  1. 过滤器也可以接收额外参数、多个过滤器也可以串联
  2. 并没有改变原本的数据, 是产生新的对应的数据
  3. 不是必须的属性,完全可以用 methods 和 computed 实现下面代码中的过滤功能
  4. 当全局过滤器和局部过滤器重名时,会采用局部过滤器
<!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 指令

  1. 本质是一个特殊属性,Vue 实例创建完毕并接管容器后,会删掉 v-cloak 属性
  2. 使用 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

  1. v-once 所在节点在初次动态渲染后,就视为静态内容了
  2. 以后数据的改变不会引起 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性能优化

  1. 跳过其所在节点的编译过程
  2. 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译
<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 基础快速入门(一)相关推荐

  1. Vue 基础快速入门(二)

    Vue 组件化编程 模块, 组件, 模块化与组件化 模块 理解:向外提供特定功能的 js 程序, 一般就是一个 js 文件 为什么:js 文件很多很复杂 作用:复用 js,简化 js 的编写, 提高 ...

  2. (vue基础试炼_01)使用vue.js 快速入门hello world

    文章目录 一.需求案例 二.案例实现 2.1. 原始js写法 2.2. 怎样使用vue.js ? 2.3. 使用vue.js 写法 三.案例vue简述? 四.案例趣味延伸 五.表达值作用及嘱咐语 一. ...

  3. .NET Core实战项目之CMS 第六章 入门篇-Vue的快速入门及其使用

    写在前面 上面文章我给大家介绍了Dapper这个ORM框架的简单使用,大伙会用了嘛!本来今天这篇文章是要讲Vue的快速入门的,原因是想在后面的文章中使用Vue进行这个CMS系统的后台管理界面的实现.但 ...

  4. Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 4. 函数

    什么样的程序员才是优秀的程序员?咪博士认为"慵懒"的程序员才是真正优秀的程序员.听起来不合逻辑?真正优秀的程序员知道如何高效地工作,而不是用不止境的加班来完成工作任务.函数便是程序 ...

  5. 零基础快速入门web学习路线(含视频教程)

    下面小编专门为广大web学习爱好者汇总了一条完整的自学线路:零基础快速入门web学习路线(含视频教程)(绝对纯干货)适合初学者的最新WEB前端学习路线汇总! 在当下来说web前端开发工程师可谓是高福利 ...

  6. python海龟教程_Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 7. 条件循环...

    条件循环能够让程序在条件成立时(即为真时)重复执行循环体中的语句.如果条件一直成立(即永远不会为假),则循环会一直进行下去,不会停止.如果初始时,条件不成立,则循环 1 次也不会执行.Python 中 ...

  7. 【Python零基础快速入门系列 | 03】AI数据容器底层核心之Python列表

    • 这是机器未来的第7篇文章 原文首发地址:https://blog.csdn.net/RobotFutures/article/details/124957520 <Python零基础快速入门 ...

  8. 【Python零基础快速入门系列 | 07】浪漫的数据容器:成双成对之字典

    这是机器未来的第11篇文章 原文首发链接:https://blog.csdn.net/RobotFutures/article/details/125038890 <Python零基础快速入门系 ...

  9. ROS2零基础快速入门

    ROS2入门最快需要多少时间?3天: ROS2开发一款基础机器人需要多久?3个星期: ROS2怎么才能算"精通"?不可能,3年也不行-- 如何判断一款通用性软件成熟并可以投入精力去 ...

最新文章

  1. NCBI下载SRA数据的4种方法
  2. 在Tomcat中部署Java Web应用程序几种方式
  3. nvidia 程序安装失败
  4. c++原型模式(Prototype)
  5. linux体验服务器,体验Ubuntu做服务器
  6. Vue项目如何实现国际化?分享一下基于vue-i18n实现国际化的经验
  7. LeetCode 1455. 检查单词是否为句中其他单词的前缀
  8. 论文必备神器,1行代码搞定Latex公式编写,这个4.6M的Python小插件
  9. 熟悉 CMake(一)
  10. 分享7个超实用的Emmet(zen coding)HTML代码使用技巧
  11. android webview 百度地图,Android WebView显示地图
  12. 解决Solidworks 2016 安装注册Activator.GUI.SSQ卡顿 闪退 崩溃等问题
  13. 最强卸载工具,彻底卸载无残留IObit Uninstaller 9.0.2.40
  14. 《Introduction To Modern Cryptography》读书笔记一
  15. RAdam和LookAhead合二为一
  16. Arduino基础入门篇25—红外遥控
  17. 怎么查看自己CSDN博客的具体排名数?
  18. 【读书笔记】好好思考-成甲
  19. 算法工程师,上岸了!
  20. 自动登录XP其实很轻松

热门文章

  1. 移动电子商务≠移动购物,前者远远大于后者
  2. 开家创意家饰店 巧赚主妇钱
  3. java jni释放_JNI 资源释放
  4. 【工作流引擎】BPMN2.0介绍
  5. RANSAC算法(一)
  6. Java 中 Boolean 和 boolean的区别
  7. Git语法、常用命令
  8. 大班我和计算机比本领教学反思,大班语言《谁的本领大》教案反思
  9. 中国冶金工业节能减排行业十四五发展方向及投资战略决策建议报告2021-2027年
  10. iis配置web服务器_web服务器配置详解