#vue.js
1.为什么要学习vue
- vue能减少不必要的DOM操作,提高渲染效率
- 双向数据绑定的概念
- 只关心业务逻辑,不再关心DOM是如何渲染的了
2.什么是框架
- 一套完整的解决方案
- 对项目的侵入性较大,项目如果要更换框架,则要重新架构整个项目
3.MVVM
-
MVVM把前端的视图层,把每个页面分成了三部分Model、View、VM
-
提供了数据双向绑定的思想(由VM提供)
-
Model:每个页面中单独的数据,获得的JSON数数据数组
-
View:就是每个页面中的html结构
-
VM:是一个调度者,分割了M和V,实现V和M之间的相互调用
-
前端的框架不提倡我们再手动去操作DOM元素,如:
$('#id').text('hello')
-
V:视图,即vue实例所控制的元素区域
<div id="app"> <p>{{ msg }}</p> </div>
-
VM:创建出来的vm就是VM,数据之间的调度者
var vm = new Vue({ el: '#app', //表示当前new的这个vue实例,要控制页面上的哪个区域 data:{ //data存放el中要用到的数据 msg:'vue.js' } })
-
M:页面中保存的数据
VM中的data就是M,用来保存页面中的数据
4.v-cloak
-
解决差值表达式闪烁问题
<p> {{ msg }}</p>
当js文件的渲染未完成时,html结构中的p显示的是 {{msg}} 的字符串,当js渲染完成后才能显示 msg 的值,因此会有闪烁。
解决方法:
<style> [v-cloak]{ display:none; } </style> <div id="app"> <p v-cloak>{{ msg }}</p> </div>
这样就可以在未渲染完成时先隐藏p,等js加载完成后再显示出来。
5.v-text
<h4 v-text="msg"></h4>
显示出来和 {{ msg }} 的效果相同
6.插值表达式和v-text的区别
- 插值表达式可以在数据前后添加固定字符
- v-text没有闪烁问题,即js全部渲染完成后才显示出来数据
- v-text会覆盖元素中原本的内容,而插值表达式只会替换自己的占位符
- 插值表达式和v-text都会把内容转换为字符串的形式输出
7.v-html
-
覆盖元素中的所有内容,然后把内容当成html的标签渲染在页面上
<div v-html="msg2"></div> ... data:{ msg2:'<h1>我是一个H1</h1>' } ...
8.v-bind:绑定元素的属性(缩写为 :
- v-bind会把后面的 msg 当成一个js变量来解析
- 该 msg 变量可以在后面加上任意字符串
- 如:v-bind:title=“msg + hello” 也是合法的
- 简写模式冒号加title,即代表绑定title
9.v-on:绑定事件 (缩写为 @)
var vm = new Vue({
el: '#app',
data:{},
methods:{
show(){
alert('hello');
}
}
})
10. T I P
- 在vm实例中,如果需要获取到 data 上的值,或者想要调用 methods 中的方法,那就必须通过 this.数据名 或者 this.方法名 来进行访问,这里的 vm 就代表当前的 vue实例
- VM实例会监听自身data数据的改变,只要数据一发生变化,就会自动把最新的数据同步到页面中【好处:程序员只需要关心数据,不需要关心如何渲染到页面】
11.跑马灯效果:v-on & substring
<div id="app">
<button type="button" v-on:click="roll">滚动</button>
<button type="button" v-on:click="stop">停止</button>
<p> {{ msg }} </p>
</div>
<script src="vue.js"></script>
<script>
var timer1 = null;
var vm = new Vue ({
el:'#app',
data:{
msg:'这是一个跑马灯~'
},
methods:{
roll(){
if (timer1 != null)
{
clearInterval(timer1);
}
timer1 = setInterval ( () => {
var str1 = this.msg.substring(0,1);
var str2 = this.msg.substring(1);
this.msg = str2 + str1;
},200)
},
stop(){
clearInterval(timer1);
}
}
})
</script>
12.事件修饰符 :对事件进行修饰
-
① .stop 阻止冒泡
事件有冒泡的机制,如
<div @click="start"> <div @click="end"> </div> </div>
当点击外部的div时,触发顺序为end->start,即从内至外进行冒泡。
使用.stop修饰符可以在被修饰的地方阻止冒泡事件
<div @click="start"> <div @click.stop="end"> </div> </div>
此时点击外部的div,只会触发end,而不会再触发start(在end处被阻止)
-
② .prevent 阻止默认行为,实行新添加的行为
<a href="http://www.baidu.com" target="_blank" @click.prevent="waibu">点击去百度</a>
点击上面的a标签,不会跳转到新的页面,而是调用methods中的wa
ibu方法
-
③.capture 捕获事件,从外向内执行
冒泡事件是从里向外执行,而捕获事件则是从外向内执行。
<div @click.capture="waibu"> <button type="button" @click="neibu">button</button> </div>
此时点击Div,会先触发waibu,再触发neibu
-
④.self只有事件是在元素自身的时候,才会触发
13.v-model实现数据双向绑定
-
v-bind只能实现数据的单向绑定,从 M 绑定到 V
-
使用 v-model 可以实现数据的双向绑定
<div> {{ msg }} </div> <input type="text" v-model="msg">
-
v-model 只能用在表单元素中!
14.简易的计算器:v-model 的应用
<input type="text" v-model='n1'>
<select name="" id="" v-model="opt">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="text" v-model='n2'>
<input type="button" value="=" @click="cal">
<input type="text" v-model='result'>
cal(){
var codeStr = 'parseInt(this.n1)' + this.opt + 'parseInt(this.n2)';
this.result = eval(codeStr);
1.使用字符串拼接,拼接出计算代码语句
2.使用eval解析代码语句并执行
}
15.设置class样式
<h1 v-bind:class="['class1','class2','class3']">
这是一个h1
</h1>
- 给元素绑定 class 即可设定该 class 下的样式,要注意:v-bind 会把后面的字符串当成变量,在vue中寻找该变量的值。因此,如果是写在 style 标签中的类名,那要把类名写成 字符串 的形式再进行绑定。
<h1 v-bind:class="['thin','red',flag?'active':'']">
这是一个很大的h1
</h1>
- 这里使用三元表达式来决定是否加入 active 类
<h1 v-bind:class="['thin','red',{'active':flag}]">
这是一个很大的h1
</h1>
- 这里使用了 {‘active’:flag} 来决定是否加入 active 类名,flag的值来自于data
html:
<h1 v-bind:class="classCss">
这是一个很大的h1
</h1>
js:
classCss:{red:true,thin:true,italic:true}
//直接把要的类写成一个 **对象**,再把对象直接绑定在元素的class中
16.设置style样式
<h1 v-bind:style="{color:'red','font-weight':200}">
这是一个很大的h1
</h1>
- 使用 v-bind 绑定元素的样式属性。
- 当属性名有- 时,需要给属性名加上引号
- 也可以在 data 中定义对象,表示 style ,再绑定到元素上
17.v-for
- 循环普通数组
<p v-for="(item,i) in list"> 索引值:{{ i }} 数据值:{{ item }} </p>
js:
data:{
list:[0,1,2,3,4,5,6]
}
- 循环对象数组
<p v-for="(item,i) in list"> 索引值:{{ i }} id:{{ item.id}} 姓名:{{ item.name }} </p>
js:
data:{
list:[
{id:1,name:'n1'},
{id:2,name:'n2'},
{id:3,name:'n3'},
{id:4,name:'n4'}
]
}
- 循环对象
<p v-for="(val,key,i) in user"> 值是:{{ val }} 键是:{{ key }} 索引:{{ i }} </p>
js:
data:{
user:{
id:1,
name:'tony',
gender:'male'
}
}
- 迭代数字
<p v-for="count in 10">这是第 {{ count }} 次循环</p>
- 使用 key 来指定唯一的数据
<div id="app">
<label>输入编号</label><input type="text" v-model="id">
<label>输入姓名</label><input type="text" v-model="name">
<input type="button" @click="add" value="添加">
<p v-for="item in list" v-bind:key="item.id">
<input type="checkbox"/>
id:{{ item.id }} name:{{ item.name }}
</p>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue ({
el:"#app",
data:{
id:'',
name:'',
list:[
{id:1,name:'a'},
{id:2,name:'b'},
{id:3,name:'c'},
{id:4,name:'d'},
]
},
methods:{
add(){
this.list.unshift({id:this.id,name:this.name})
}
}
})
</script>
当使用 v-for 循环的时候,如果要对循环出来的数据做唯一处理,则可以为每个数据绑定唯一的 key (可以是number或者string)
18.v-if
<button type="button" @click="flag=!flag">切换</button>
<h1 v-if="flag">v-if</h1>
<h1 v-show="flag">v-show</h1>
-
v-if:每次都会创建或删除元素,有较高的切换性能损耗
-
v-show:不对DOM进行删除创建操作,每次只是改变了 display 的样式
如果涉及到元素频繁的切换,则最好不要用 v-if
如果元素可能永远也不会被显示,则推荐使用v-if
19.过滤器
- 过滤器只能用在两个地方:差值表达式 + v-bind
- 格式 {{ name | nameope }}
- 上式指:在输出name之前,先用nameope对数据进行过滤
20.设置过滤器
Vue.filter(‘filter-name’,function(data){
…
})
- 过滤器采用的是就近原则,当私有过滤器和全局过滤器重复时(同名),采用的是私有的过滤器
21.☆模板字符串
${变量1}-${变量2}
使用 tab 键上的反引号,内部的每个变量用 ${} 包括,就可以实现字符串的拼接了
22.通过日期字符串来解析日期
- var newdate = new Date ( ) 得到的日期是一个字符串形式
- 如果要解析字符串日期,可以
- var mydate = new Date (datestr) //把日期字符串作为参数传进去
- var y = mydate.getFullYear()
- var m= mydate.getMonth()+1
- var d = mydate.getDate()
23.补齐字符串长度
- padStart(length,str) //如果长度不够length,则在字符串的开头补上str
- padEnd(length,str) //如果长度不够length,则在字符串的结尾补上str
- 可用于时间的补0,但是要把getFullYear后的数据 toString().paadStart()
24.按键修饰符
-
v-on:keyup.enter = “” 代表党抬起回车键时触发
-
v-on:keyup.13 = “” 代表抬起 keyCode 为 13的按键时触发
-
但是不是每个按键都有名字定义,大部分按键只有按键码,因此把按键名和按键码相绑定
-
Vue.config.keyCodes.f2 = 112
25.自定义指令
- 自定义指令都要以 v- 开头
- 在定义的时候,不需要加 v- 前缀,但是在调用的时候,必须在指令名称前面加上 v- 前缀
- Vue.directive(‘指令名’,{对象})
- 第二个参数是一个对象,里面包含一些函数,这些函数会在特定的阶段实行
// 使用 Vue.directive() 定义全局的指令 v-focus
Vue.directive('focus', {
bind: function (el) { // 每当指令绑定到元素上的时候,会立即执行这个 bind 函数,只执行一次
// 注意: 在每个 函数中,第一个参数,永远是 el ,表示 被绑定了指令的那个元素,这个 el 参数,是一个原生的JS对象
// 在元素 刚绑定了指令的时候,还没有 插入到 DOM中去,这时候,调用 focus 方法没有作用
// 因为,一个元素,只有插入DOM之后,才能获取焦点
// el.focus()
},
inserted: function (el) { // inserted 表示元素 插入到DOM中的时候,会执行 inserted 函数【触发1次】
el.focus()
// 和JS行为有关的操作,最好在 inserted 中去执行,放置 JS行为不生效
},
updated: function (el) { // 当VNode更新的时候,会执行 updated, 可能会触发多次
}
})
- 和样式相关的,一般可以写在 bind 函数中
- 和 js 行为相关的,可以写在 inserted 函数中
// 自定义一个 设置字体颜色的 指令
Vue.directive('color', {
// 样式,只要通过指令绑定给了元素,不管这个元素有没有被插入到页面中去,这个元素肯定有了一个内联的样式
// 将来元素肯定会显示到页面中,这时候,浏览器的渲染引擎必然会解析样式,应用给这个元素
bind: function (el, binding) {
// el.style.color = 'red'
// console.log(binding.name)
// 和样式相关的操作,一般都可以在 bind 执行
// console.log(binding.value)
// console.log(binding.expression)
el.style.color = binding.value
}
})
- el 代表绑定了该指令的元素,binding代表该元素设置的一些属性
26.生命周期
- 从Vue实例创建、运行、到销毁期间,总是伴随各种各样的事件,这些事件,统称为生命周期
- 生命周期函数:和data\methods同级的一类函数
- beforeCreate ( ) { } // 第一个生命周期函数,表示实例完全创建之前调用的函数
- 在 beforeCreate 执行时,data 和 methods 都还没有定义,因此无法调用其中的元素
- created ( ) {} // 第二个生命周期函数,调用时 data 和 methods 都已经被初始化了
- 如果要调用 methods 的方法 ,或者操作 data 中的数据,最早也要在created 函数中才行
- beforeMount ( ) { } //第三个生命周期函数,Vue实例创建完成后,要把创建好的模板渲染到页面中去。beforeMount 函数就是在把模板渲染到页面之前所调用的函数。
- beforeMount 执行的时候,模板已经在内存中编译好了,但是还没有挂载到页面中。(即,数据还没有渲染到页面中)
- mounted ( ) { } //第四个生命周期函数,此时页面已经被渲染好了,是实例创建期间的最后一个生命周期函数,表示 Vue 实例已经完全被创建好了,如果没有后续操作的话,会静静的躺在内存中一动不动。
27.组件 创建组件的方式1
- 组件的理解:一个可以自定义的标签
- Vue.component(‘组件名’,Vue.extend({
- template:‘
组件内容
’
- template:‘
- }))
- 第一个参数是组件的名称,在html中,用组件的名称来引用这个组件
- template就是要展示的组件的内容
- 重点:组件也有data、方法、生命周期函数,可以把他当成一个实例来看待
28.创建组件的方式2
- Vue.component(‘组件名’,{
- template:‘
哈哈哈
’
- template:‘
- })
sum:无论是哪种方式创建出来的组件,组件里面的template都只能有且只有一个唯一的 根元素
29.在html中定义组件
js:
Vue.component('mycom',{
template:'#tmpl'
})
html:
<template id="tmpl">
<div>
<h3></h3>
<h3></h3>
<h3></h3>
</div>
</template>
//注意,使用这种方法定义的template标签,要写在Vue实例范围的外面,否则template标签也会出现
sum:定义的全局组件在整个html文档中都可以使用
如果是在Vue实例中定义的组件,则只能在该实例允许的范围之内使用
var vm = new Vue({
el:"#app",
data:{},
methods:{},
components:{
login:{ // 定义login组件,只能在app中使用
template:'<h3>呵呵哒</h3>'
}
}
})
30.组件中的data
-
① 组件可以有自己的data数据
-
② 实例中的data可以是一个对象,但是组件中的data必须是一个方法
components:{ com1:{ template:'<h1>{{ msg }}{{ info }}</h1>' data(){ return { msg:'hello', info:'joey' } } } }
-
③ 这个方法的内部还必须返回一个对象
-
④ 组件中的 data 使用方式和实例中的data使用方式一样
31.父组件向子组件传值:通过属性绑定的形式传递
子组件和父组件的定义:
如果一个组件出现在另一个组件的内部,则这个组件是外层组件的子组件
<div id="app3">
<applecomponent v-bind:b="vparam"></applecomponent>
<mycomponent v-bind:b="vparam"></mycomponent>
<templecomponent v-bind:b="vparam"></templecomponent>
</div>
如图,app3是一个实例,可以看成一个大的组件,其中的mycomponent是一个全局定义的组件,此时,全局定义的组件可以从其所在实例中继承数据。
-
<div id="app"> <p>{{ msg }}</p> <com1 v-bind:parentdata="msg"></com1> // 1.通过属性绑定,把父组件的数据赋值给com1组件 </div> <script> var vm = new Vue({ el: '#app', data:{ msg:'hello' }, components:{ com1:{ template:'<h3>{{ parentdata }}</h3>', props:['parentdata'] //2.子组件要获取父组件 } } }) </script>
- 注意:子组件的props是只读的数据,尽量不要更改。
32.父组件向子组件传递方法
-
在父组件的methods中定义的方法,可以通过方法绑定,将其加载到子组件中
html: <com1 v-on:func="show"></com1> js: var vm = new Vue({ el:"#", methods:{ show(){ //show函数 } } })
33.ref获取DOM元素
<div id="app"> <p ref="myP">今天的天气不错</p> <button type="button" @click="say">say</button> </div> <script> var vm = new Vue({ el: '#app', methods:{ say(){ alert(this.$refs.myP.innerText) } } })
ref不仅可以获得DOM,还可以获得组件(的数据和函数等)
34.watch函数监视
- 在vue实例中,加入watch属性,可以监视data中发生改变的那个数据
<div id="app">
<input type="text" v-model="msg">
</div>
<script>
var vm = new Vue({
el: '#app',
data:{
msg:'vue.js'
},
watch:{
msg:function(){ //当msg发生改变时,会自动触发该函数
console.log('监听msg');
}
}
})
</script>
``