一、Vue核心
1.1 简介
动态构建用户界面的渐进式JavaScript框架
Vue的特点
- 遵循MVVM模式
- 编码简洁,体积小,运行效率高,适合移动/PC端开发
- 它本身只关注UI,可以引入其它第三方库开发项目
- 借鉴 Angular 的模板和数据绑定技术
- 借鉴 React 的组件化和虚拟DOM技术
Vue周边库
- vue-cli:vue脚手架
- vue-resource
- axios
- vue-router:路由
- vuex:状态管理
- element-ui:基于vue的UI组件库(PC端)
1.2 初识Vue
开发环境部署
下载vue开发者工具
Vue.js和Vue.js.min
关闭生产提示
设置图标
强制刷新
shift+浏览器的刷新
正常请求,如果没有就不在请求了。所以可能看不到一些找不到图标的报错
Hello World
- 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;
- root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;
- root容器里的代码被称为【Vue模板】;
- Vue实例和容器是一一对应的(不能一对多,也不能多对一);
- 真实开发中只有一个Vue实例,并且会配合着组件一起使用;
- {{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性
- 一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新(MVVM)
注意区分:JS表达式和JS代码(语句):
1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
(1)a
(2)a+b
(3)demo(1)
(4)x === y ‘a’ : ‘b’
2.js代码(语句)
(1)if(){}
(2)for(){}
表达式就是特殊的JS语句,能控制代码能否执行的就是JS语句
1.3 模板语法
概念: 容器里面的代码就是模板语法
模板语法分为两大类:
差值语法:
功能:用于解析标签体内容。
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。
指令语法:
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)
备注:Vue中有很多的指令,且形式都是:v-
举例:v-bind:hred=“xxx” 或 简写为 :href=“xxx”,xxx同样要写js表达式,且可以直接读取到data中的所有属性。
<a href="url"></a> <!-- 此时的url只是一个字符串 --> <a href={{url}}></a> <!-- 差值写在属性的写法已经被Vue弃用 --> <a v-bind:href="url"></a> <!-- 正确用法 --> <a :href="url"></a> <!-- 简写 -->
1.4 数据绑定
Vue中有2种数据绑定的方式:
单向绑定(v-bind):数据只能从data流向页面。
双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
备注:
1.双向绑定一般都应用在表单元素上(如:input、select等)
2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。
<!-- 单向数据绑定 !--> <input type="text" :value="name"> <!-- 双向数据绑定 !--> <input type="text" v-model="name">
错误示例:
以下代码是错误的,因为v-model只能应用在表单类元素(输入类元素)上
<h2 v-model:x="name">hello</h2>
el和data的两种写法
el有2种写法:
(1)new Vue时候el属性;
(2)先创建Vue实例,随后再通过vm.$mount(’#root’)指定el的值
data有2种写法:
(1)对象式
(2)函数式
如何选择?目前哪种写法都可以,以后学到组件时,data必须使用函数式,否则会报错
一个重要的原则:
只要是Vue所管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了,而是window
MVVM
vm就是vue的实例对象
MVVM模型:
M:模型(Model):data中的数据
V:视图(View):Vue模板
VM:视图模型(ViewModel):Vue实例对象(绑定数据,dom监听)
观察发现:
data中所有的属性,最后都出现在了vm身上
vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接访问
我们来重点理解中间的视图模型(VM)
中间的vm帮我们干了很多事,前端的框架都是这个套路
把一堆乱七八糟的数据和一堆dom结构,vue呢在中间做了个连接,它就是中间一个桥梁一个纽带
你把数据放在我要求放好的位置,然后你写出这种模板代码。模板里具体怎么插入值那你就要学习我的语法,像vue的插值语法啊,指令啊之类的。然后框架开始工作就可以将左边和右边的相互连接起来,并且还能给你承诺数据怎么变页面就怎么变
代码理解
我们也可以打印vm自带的变量或方法
1.5 事件
事件处理
- 使用 v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
- 事件的回调需要配置在methods对象中,最终会再vm上;
- methods中配置的函数,不要用箭头函数!否则this就不是vm了而是window;
- methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;
- @click=“demo” 和 @click="demo(e v e n t ) " 效 果 一 致 , 前 者 默 认 参 数 就 是 事 件 对 象 , 后 者 要 用 event)" 效果一致,前者默认参数就是事件对象,后者要用event)"效果一致,前者默认参数就是事件对象,后者要用event才能生成事件对象,并且可以传多个参数;
备注:method上面的方法最终也会出现在vm上面,但它并没有作数据代理,因为没有必要,函数一旦定义好就直接拿来用。
测试给函数传参
事件修饰符
事件冒泡就是事件一个接一个的发生
prevent
阻止默认事件(常用)
本来弹窗完会跳转到百度(跳转到百度就属于默认事件),但是加上事件修饰符prevent的话弹完窗就不会跳到百度了
<a href="http://www.baidu.com" @click.prevent="showInfo">点我跳转到百度</a>
stop
阻止事件冒泡(常用)
触发完按钮的事件,又会触发div的事件。事件一个接一个的发生了这就叫事件冒泡
在单机事件后加上stop即可阻止事件冒泡
<div class="demo1" @click="showInfo"> <button @click.stop="showInfo">点我提示信息</button> <!-- 没加会触发外层事件,加了则不会 --> </div>
once
事件只触发一次(常用)
本来是点一次弹一次,加上once后只会弹一次
<button @click.once="showInfo">点我弹窗</a>
captur
使用事件的捕获模式
事件流 分为 捕获 和 冒泡
- 当点击div2的时候先经过两个阶段:事件捕获=>事件冒泡,默认是事件冒泡处理事件;
- 捕获阶段由外往内,冒泡阶段由内往外;
self
只有event.target是当前操作的元素时才触发事件
<div class="box1" @click.capture="showMsg(1)"> div1 <div class="box2" @click="showMsg(2)"> <!-- 没加输出1,2,加了输出2,1 --> div2 </div> </div>
passive
先执行默认行为,后执行回调函数
键盘事件
1.Vue中常用的按键别名:
回车 => enter
删除 => delete(捕获“删除(delete)”和“退格(BackSpace)”键)
退出 => esc
空格 => space
换行 => tab(特殊,必须配合 keydown 去使用)
上 => up
下 => down
左 => left
右 => right
其他的键盘事件类似
2.Vue未提供别名的案件,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
3.系统修饰键(用法特殊):ctrl、alt、shift、meta
(1)配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其它键,事件才被触发。(此时的e.key值是其它键,而不是系统修饰键)
(2)配合keydown使用:正常触发事件。
事件总结
修饰符小技巧:事件修饰符可以连着写
<!-- 阻止默认事件和冒泡 --> <div class="demo1" @click="showInfo"> <a href="http://www.atguigu.com" @click.stop.prevent="showInfo">点我提示信息</a> </div> <!-- 按 ctrl + y 才触发(系统修饰符 + 键名) --> <input type="text" placeholder="按下回车提示输入" @keyup.ctrl.y="showInfo">
1.6 计算属性
姓名案例
将数据展示到页面时要清楚,你模板里写的是指令还是插值
Vue官方建议组件模板应该质包含简单的表达式,复杂的表达式则应该重构为计算属性或方法
差值语法实现:
<div id="root"> 姓:<input type="text" v-model="firstName"> 名:<input type="text" v-model="lastName"> 姓名:<span>{{firstName.slice(0,3)}}-{{lastName}}</span> </div> <script> const vm = new Vue({ el: '#root', data: { firstName: '张', lastName: '三' } }) </script>
methods实现:
<div id="root"> 姓:<input type="text" v-model="firstName"> 名:<input type="text" v-model="lastName"> 姓名:<span>{{fullName()}}</span> <button @click="fullName">点我</button> </div> <script> const vm = new Vue({ el: '#root', data: { firstName: '张', lastName: '三' }, methods: { fullName() { return this.firstName + '-' + this.lastName } // this指向vm } }) </script>
注意methods方法在绑定事件的时候才可以省略小括号,在差值里不能
- 只要data中的数据发生改变,Vue就会重新解析模板,只有重新解析模板才会拿到最新的值
computed实现:
<div id="root"> 姓:<input type="text" v-model="firstName"> 名:<input type="text" v-model="lastName"> 姓名:<span>{{fullName}}</span> </div> <script> const vm = new Vue({ el: '#root', data: { firstName: '张', lastName: '三' }, computed: { fullName: { get() { // 此处的this是vm return this.firstName + '-' + this.lastName } } } }) </script>
计算属性
对于Vue来说,data里的配置项就是属性 。
而计算属性,就是拿着写完的属性去加工计算,生成一个全新的属性。
计算属性直接被挂载到vm上,直接读取使用即可(_data里面没有计算属性)。
const vm = new Vue({ el: '#root', data: { firstName: '张', lastName: '三' }, computed: { fullName: { get() { // 此处的this是vm return this.firstName + '-' + this.lastName; } } } })
get什么作用?
当有人读取fullName时,get就会被调用,且返回值就作为fullName的值。
(底层就是用Object.defineProperty的getter/setter实现的)
get什么时候被调用?
1.初次读取时会执行一次(往后就会取缓存里的数据)
2.所依赖的数据发生变化时会被再次调用(所以不用担心修改了值还会从缓存里获取)
<!-- Vue模板里有4个fullName,为什么get只被调用了一次? 因为Vue底层为computed做了一个缓存机制,重复的计算属性会到缓存里面获取 --> <div id="root"> <span>{{fullName}}</span> <span>{{fullName}}</span> <span>{{fullName}}</span> <span>{{fullName}}</span> </div> <script> const vm = new Vue({ el: '#root', data: { firstName: '张', lastName: '三' }, computed: { fullName: { get() { console.log('get被调用了'); // 只输出了一次 “get被调用了” return this.firstName + '-' + this.lastName } } } }) </script>
set什么时候被调用?
当fullName被修改时。
如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生变化。
<!-- 当fullName被修改时页面并没有发生变化,原因是set并没有改到firstName和lastName,它只做了输出。 所以要想页面也发生变化,那就得给set做一个加工,让它修改到firstName和lastName。 --> <script> const vm = new Vue({ el: '#root', data: { firstName: '张', lastName: '三' }, computed: { fullName: { get() { console.log('get被调用了'); // 只输出了一次 “get被调用了” return this.firstName + '-' + this.lastName }, set(value) { console.log('set', value); // 格式:张-三 const arr = value.split('-'); this.firstName = arr[0]; this.lastName = arr[1]; } } } }) </script>
computed对比methods:
computed有缓存机制(复用),效率更高、调试方便(devtools上会有一个computed的分类)。
methods函数出现几次就调用几次,效率比较低。