vue核心
一、vue概念
V+ue.js是套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue采用自底向上增量开发的设计。Vue 的核心库只关注/图层,并且非常容易学习,非常容易与其它库或已有项目整合。另一方面,Vue 完全有能力驱动采用单文件组件和Vue生态系统支持的库开发的复杂单页应用(单页面开发SPA)
渐进式框架:可以理解为上手简单,入门简单,但是可以渐近提高框架等级 视图层:之前我们的express它是一个MVC的框架 SPA:称之为单页面开发,是目前开发的主流,当前阶段能够很好的实现SPA开发的框架主要有三个,分别是vue/react/angular
安装
1、安装dev tools
2、安装vue2,在node中安装
yarn add vue@2
使用
<script src="../js/vue.js"></script
二、初识Vue
想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象 demo容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法 demo容器里的代码被称为【Vue模板】 Vue实例和容器是一一对应的 真实开发中只有一个Vue实例,并且会配合着组件一起使用 { {xxx}}是Vue的语法:插值表达式,{ {xxx}}可以读取到data中的所有属性 一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新(Vue实现的响应式)
注意:vue实例接管的容器不能是body更不能接管html
当vue一旦接管某一个容器以后,这个容器里面所有的东西都可以通过vue来操作,如数据,事件,样式等
<!-- 引入vue -->
<script src="../js/vue.js"></script>
</head>
<body>
<!-- 第一个容器 -->
<div class="box1">
<h1>你好{
{name}}</h1>
</div>
<!-- 第二个容器 -->
<div class="box2">
<h1>你好{
{name.toUpperCase()}},{
{ Date.now() }}</h1>
</div>
</body>
</html>
<script type="text/javascript">
Vue.config.productionTip = false;
// 第一个vue实例
new Vue({
el: '.box1',
data: {
name: '初始vue1'
}
})
// 第二个vue实例
new Vue({
el: '.box2',
data: {
name: '初始vue2'
}
})
</script>
三、模板语法
1、插值语法{ {}}
功能:用于解析标签体内容
语法:{ {xxx}},xxx是js表达式,且可以直接读取到data中的所有属性
<div class="box">
<!-- 插值语法 -->
<h1>模板语法之:{
{value}}</h1>
<!-- 对象语法.的方式 -->
<a href="">{
{prosion.name}}的年龄为{
{prosion.age}}</a>
</div>
<script src="../js/vue.js"></script>
<script>
new Vue({
el: ".box",
data: {
value: '插值语法',
// data的属性的key对应的values是一个对象时
prosion: {
name: '张三',
age: 18
}
}
})
</script>
2、指令语法v-xx
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)
语法:
如v-bind指令用于数据绑定:v-bind:href=“xxx” 或 简写为 :href=“xxx”,xxx同样要写js表达式,且可以直接读取到data中的所有属性
注意:[v-bind:] 可以简写为[:]
3、模板中的js表达式
正确表达式:
1、{ { number + 1 }} 2、{ { ok ? 'YES' : 'NO' }} 3、{ { message.split('').reverse().join('') }} 4、<div v-bind:id="'list-' + id"></div>
错误表达式:
<!-- 这是语句,不是表达式 --> { { var a = 1 }} <!-- 流控制也不会生效,请使用三元表达式 --> { { if (ok) { return message } }}
<div class="box">
<!-- 指令语法v-bind: -->
<a v-bind:href='url'>百度一下小写</a>
<a v-bind:href="url.toUpperCase()">百度一下大小</a>
<!-- [v-bind:] 可以简写为[:] -->
<a :href="url.toUpperCase()">百度一下大小</a>
</div>
<script src="../js/vue.js"></script>
<script>
new Vue({
el: ".box",
data: {
url: 'http://www.baidu.com',
}
})
</script>
四、数据绑定
1、单向数据绑定
单向绑定(v-bind):数据只能从data流向页面
当data的值改变时,v-bind绑定的值会跟着改变,但是当反过来时v-bind绑定的值改变时,data的值不会跟着改变
单向绑定<input type="text" v-bind:value="name">
单向绑定简写<input type="text" :value="name">
2、双向数据绑定
双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data
当data的值改变时,v-model绑定的值会跟着改变,当反过来时v-bind绑定的值改变时,data的值也会跟着改变
注意:
1.双向绑定一般都应用在表单类元素上(如:input、select等)
2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值
双向绑定<input type="text" v-model:value="name">
双向绑定简写<input type="text" v-model="name">
使用v-model收集表单数据
收集表单数据:
若:text框,则v-model收集的是value值,用户输入的就是value值。
若:radio为,则v-model收集的是value值,且要==给标签配置value值==。
若:为checkbox
没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
配置input的value属性:
v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
v-model的初始值是数组,那么收集的的就是value组成的数组
v-model的三个修饰符:
- lazy:失去焦点再收集数据
- number:输入字符串转为有效的数字
- trim:输入首尾空格过滤
<div class="box"> <form @submit.prevent="submit"> <!--.trim去除前后空格 --> 用户名<input type="text" v-model.trim="userInfo.username"><br> 密码:<input type="password" v-model="userInfo.password"><br> <!-- .number字符串装转为number--> 年龄:<input type="number" v-model.number="userInfo.age"><br> 性别: 男<input type="radio" name="sex" v-model="userInfo.sex" value="boy"> 女<input type="radio" name="sex" v-model="userInfo.sex" value="girl"><br> 爱好: <input type="checkbox" name="hobby" v-model="userInfo.hobby" value="sing"> <input type="checkbox" name="hobby" v-model="userInfo.hobby" value="jump"> <input type="checkbox" name="hobby" v-model="userInfo.hobby" value="rap"><br> 所在地: <select name="" id="" v-model="userInfo.address"> <option value="">--请选择--</option> <option value="北京">北京</option> <option value="上海">上海</option> <option value="深圳">深圳</option> </select><br> <!--.lazy失去焦点再更新值--> 个人简介:<textarea cols="30" rows="10" v-model.lazy="userInfo.introduce"></textarea> <br> 阅读并接受用户协议:<input type="checkbox" v-model="userInfo.agree"><br> <input type="submit"> </form> </div> </body> <script src="../js/vue.js"></script> <script> let vm = new Vue({ el: '.box', data: { userInfo: { username: "", password: "", age: '', sex: "boy", hobby: [], address: "北京", introduce: "", agree: "" }, }, methods: { submit () { console.log(this.userInfo); } } }) </script>
五、el与data的两种写法
1、el的两种写法
①创建vue构造函数的实例时指定
new Vue({ // 创建vue实例对象时指定el容器 el: '.ul', // data为对象类型 data: { value1: "1", } })
②创建vue实例后通过实例对象的原型方法**$mount()**指定
// 在vue实例上挂载dom容器对象 vm2.$mount(".ul")
2、data的两种写法
①data为对象类型
new Vue({ // 创建vue实例对象时指定el容器 el: '.ul', // data为对象类型 data: { value1: "1", } }) console.log(vm);
②data为函数类型,返回值为对象类型
注意:在组件中,data必须使用函数式
let vm2 = new Vue({ // data是一个函数返回值为一个对象 data: function () { return { value1: "你好" } } })
六、MVVM模型:
M:模型(Model) :对应 data 中的数据
V:视图(View) :模板
VM:视图模型(ViewModel) : Vue 实例对象
Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r4YAtIiu-1664507085274)(C:\Users\QuMing\Desktop\vue\资源\笔记图片\Snipaste_2022-08-22_19-20-38.png)]
对应代码的部分
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IXFVjiLt-1664507085275)(C:\Users\QuMing\Desktop\vue\资源\笔记图片\Vue数据代理.png)]
1、data中的属性都会出现在vue实例对象上,
2、vue实例对象上的所有属性及 原型上所有属性在vue模板中都可以使用
柒、数据代理
数据代理: 通过一个对象代理对另一个对象中属性的操作
1、Object.defineProperties的 get、set方法
let name = 'zs';//第三方数据 let age = 20;//第三方数据 let use = { } Object.defineProperties(use, { name: { get: function () { return name//过去name属性时返回第三方name }, set: function (value) { name = value//设置name属性时不是设置自身name而是设置第三方name的值,这样的话name的值就是动态变化的 } }, age: { get: function () { return age }, set: function (value) { age = value } } })
2、数据代理,
//实际对象 let obj1 = { name: "张三" } //代理对象 let obj2 = { } // 通过代理对象的get和set来操作实际的对象属性 Object.defineProperty(obj2, 'name', { get: function () { // 获取代理对象的属性时通过get拦截实际返回的是实际对象的属性 return obj1.name; }, set: function (value) { // 修改代理对象的属性时通过get拦截实际修改的是实际对象的属性 obj1.name = value; } }) console.log(obj2.name);//张三 obj2.name = "黎明" console.log(obj2.name);//黎明 obj1.name = "zs" console.log(obj2.name);//zs
vue中的数据代理
在创建vue实例对象时,vue将data中的数据全部复制一份保存在.实例对象的_data对象中,_
然后Vue给vue实例中添加_data中同名的属性并给属性设置【访问器属性】的getter和setter方法,_
并且setter方法中会增加一个方法,这个方法会让vue重新解析模板
当实例获取_data中同名属性时,会调用访问器属性的getter方法,但返回是_data中同名的值
当实例修改_data中同名属性时,会调用访问器属性的setter方法,但修改的是_data中同名的值。
调用setter方法的同时会重新解析模板(解析模板的后续:生成新的虚拟 DOM----->新旧DOM 对比 -----> 更新页面)
这样的话当data中数据变化时,_ data中会变化,vm中也就跟着变化,
提示:我们知道vue实例对象上的所有属性及 原型上所有属性在vue模板中都可以使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4c2sgG8h-1664507085276)(C:\Users\QuMing\Desktop\vue\资源\笔记图片\Snipaste_2022-08-22_19-32-06.png)]
注意事项💡不被响应的数据
在vue2中,数组中的单元进行整体替换是不会被响应的
<body> <div class="box"> 姓名:<span>{ {arr[0].name}}</span> 年龄:<span>{ {arr[0].age}}</span> </div> </body> <script src="../js/vue.js"></script> <script> let vm = new Vue({ el: ".box", data: { // 当整体修改数组的单元时,数据不被被监事到变化,页面数据不会响应 // 当把数组的下标为0 的元素整体替换时,数据不会被监视到,页面没有响应 arr: [{ name: "张三", age: 18 }, { name: "王五", age: 20 }] }, }) </script>
先在控制台修将数组下标为0的元素整体修改、
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FGSOsTwD-1664507085277)(C:\Users\QuMing\Desktop\vue\资源\笔记图片\Snipaste_2022-08-25_17-17-27.png)]
❓ 修改后:vm中的data数据并没有变化。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ArN0TQkF-1664507085277)(C:\Users\QuMing\Desktop\vue\资源\笔记图片\Snipaste_2022-08-25_17-22-34.png)]
解决方法
1、使用vm.$set
vm.$set(vm.arr,0,{name:“zs”,age:19})
2使用入栈的方法,
m.arr.unshift({ name: ‘zs’, age: 19 })
Vue检测数据的原理
1、Vue监视数据的原理:
- vue会监视data中所有层次的数据
2、如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
对象中后追加的属性,Vue默认不做响应式处理
如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或
vm.$set(target,propertyName/index,value)
3、如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
- 调用原生对应的方法对数组进行更新
- 重新解析模板,进而更新页面
4、在Vue修改数组中的某个元素一定要用如下方法:
使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
Vue.set() 或 vm.$set()5、特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!
八、事件处理
事件绑定语法:
1、v-on:事件名=‘‘方法名’’
2、简写: @事件名=‘‘方法名’’
注意:
1、调用函数时不传参数,默认会传一个event对象
2、调用函数传参数时,如果还要使用event对象,需要要添加** e v e n t ∗ ∗ 实参, event**实参, event∗∗实参,even就是event对象
3、事件回调函数中的this指向是vm 或 组件实例对象
4、事件回调函数需要配置在methods对象中,最终会在vm上
5、如果想拿到data里面的数据,应该使用**this. d a t a ∗ ∗ ,但是可以简写,去掉 data**,但是可以简写,去掉 data∗∗,但是可以简写,去掉data也可以明出处
鼠标事件
<body> <div class="box"> <button v-on:click="fun(1,$event)">按钮1</button> <button @click="fun(1,$event)">按钮2</button> </div> </body> <script src="../js/vue.js"></script> <script> let vm = new Vue({ el: ".box", data: { value: "小白" }, // 事件的回调函数都写在methods中 methods: { fun (a, e) { console.log(a, e); // alert(`初始vue的${this.$data.value}`) alert(`初始vue的${ this.value}`) } } }) </script>
键盘事件
<body> <div class="box"> <input type="text" @keyup.enter="fun"> </div> </body> <script src="../js/vue.js"></script> <script> new Vue({ el: ".box", data: { }, methods: { fun () { console.log(event.target.value); } } }) </script>
九、事件修饰符
小技巧:修饰符可以连续写
功能性修饰符
- stop:停止事件冒泡
- prevent:阻止标签的默认行为
- once:事件只触发一次
- self:当前事件只有自己触发时才执行回调
- capture:事件捕获阶段执行
- passive:事件默认行为立即执行,无需等待回调
- native修饰符,给组件绑定事件时需要加native修饰符
针对于鼠标的
.left .right .middle
针对于键盘的修饰符
.enter .tab(必须配合keydown使用) .delete (捕获“删除”和“退格”键) .esc .space .up .down .left .right
针对于系统的修饰符(用法特殊)
- 配合keyup使用:按下修饰符键的同时,再按下其他键。随后释放其他键,事件才会触发。
- 配合keydown使用:正常触发事件。
自定义键名:Vue.config.keyCodes.自定义键名 = 键码
.ctrl .alt .shift .meta
十、计算属性computed
1、定义:要用的属性不存在,要通过已有属性计算得来
2、原理:底层借助了Objcet.defineProperty方法提供的getter和setter(计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:)
3、get函数什么时候执行?
- 初次读取计算属性时会执行一次
- 当计算属性==所依赖的属性发生改变时会被再次调用==,其他时候获取name时都是从缓存中读取的,增加效率
4、set函数什么时候执行?
- 当name属性改变时会调用set方法
5、优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便
6、注意:
- 计算属性最终会出现在vm上,直接读取使用即可
- 被vue管理的函数不要写箭头函数。
- 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变
<body>
<div class="box">
姓<input type="text" v-model:value="frilstername"><br>
名<input type="text" v-model:value="lastername"><br>
全名<span>{
{name}}</span>
</div>
</body>
<script>
let vm = new Vue({
el: ".box",
data: {
frilstername: "张",
lastername: "三"
},
methods: {
},
computed: {
name: {
// 当读取name属性时,get就会被调用,
// 注意:初次读取name属性时和所依赖的数据发生变化时才会调用get
// 其他获取name时都是从缓存中读取的,增加效率
get () {
console.log("get方法被调用了");
// get方法中的this执行vm
return this.frilstername + this.lastername
},
// 当name属性改变时会调用set方法
set (value) {
console.log("get方法被调用了");
// get方法中的this指向vm
this.frilstername = value[0]
this.lastername = value[1]
}
}
}
})
</script>
计算属性简写形式
计算属性简写前提:当所用的计算属性只考虑读取,不考虑修改时,才可以简写
<body> <div class="box"> 姓<input type="text" v-model:value="frilstername"><br> 名<input type="text" v-model:value="lastername"><br> 全名<span>{ {username}}</span> </div> </body> <script> let vm = new Vue({ el: ".box", data: { frilstername: "张", lastername: "三" }, computed: { // 当所用的计算属性只是用来获取,不会修改时,才可以简写,将计算属性的set方法省略, // 计算属性可以不写成对象形式,计算属性直接是一个函数 相当于get方法 // username: function () {return this.frilstername + this.lastername}, // 再进一步简写:无构造函数的函数,不要function username () { return this.frilstername + this.lastername } } }) </script>
十一、属性监视watch
- 当被监视的属性变化时, 回调函数自动调用, 进行相关操作
- 监视的属性必须存在,才能进行监视
- 监视的两种写法:
- (1).new Vue时传入watch配置
- (2).通过vm.$watch监视
😂 注意:watch默认不监测对象内部值的改变(只监视一层),要想深度监视需要配置开启深度监视
第一种监视方法
<body> <div class="box"> 姓名:<samp>{ {user.name}}</samp> 年龄:<span>{ {user.age}}</span> <span>{ {use}}</span> <button @click="fun">切换</button> </div> </body> <script src="../js/vue.js"></script> <script> new Vue({ el: ".box", data: { user: { name: "zs", age: 18 } }, methods: { fun () { // this._data.user.name = "王五" this.user = { name: "wz", age: 20 } } }, computed: { use () { return this.user.name + this.user.age } }, watch: { // 监视user属性,并不是监视user属性的内容发生变化 user: { // 1、handler():当user属性发生改变时,调用handler()方法 // newvalue:被监视属性变化后的值,oldvalue:被监视属性变化前的值