Vue
这里只是快速入门,并不是非常详细的学习路径
只是粗糙的刷一遍官网
vue可以不做数据查找,他进行了双向绑定MVVM
model-view
Vue初体验
vue.js的核心是允许采用简洁的模板语法来声明式地将数据渲染进DOM的系统中
使用Vue之后我们不再和 HTML直接交互了,一个 Vue 应用会将其挂载到一个 DOM 元素上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<div id="app" title="星光浮梦">{{ message }}</div>
<script> const { createApp } = Vue
createApp({ data() { return { message: 'Hello Vue!' } } }).mount('#app') </script>
|
这一段是vue3的代码,但是松哥教的是vue2,使用起来的差距还是存在的
vue2的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<div id="app" v-bind:title="title"> {{message}} </div> <script> var app = new Vue({ el: '#app', data:{ message:'hello vue!', title:'xgfm' } }) </script>
|
v-bind特性被称为指令,指令的前缀带有v-,以 表示它们是vue提供的特殊特性
条件指令
1 2 3 4 5 6 7 8 9 10 11 12 13
| <div id="app"> <div v-if="flag"> hello xgfm! </div> </div> <script> var app = new Vue({ el: '#app', data:{ flag:true } }) </script>
|
通过flag的值来使得hello xgfm是否现实出来
还有一种可以隐藏的是v-show
两者的差距在于v-if是直接将该标签从代码中隐藏起来,而v-show则是通过css样式的display设置隐藏
如果需要频繁的隐藏v-show会更加合适
循环指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <div id="app"> <table border="1"> <tr v-for="i in num"> <td v-for="g in i">{{g}}*{{i}}={{g*i}}</td> </tr> </table> </div> <script> var app = new Vue({ el: '#app', data:{ num:9 } }) </script>
|
处理用户输入
点击事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <div id="app"> <div>{{message}}</div> <button v-on:click="reverseMessage">反转消息</button> </div> <script> var app = new Vue({ el: '#app', data:{ message:"hello xgfm" }, methods:{ reverseMessage(){ this.message=this.message.split("").reverse().join("") } } }) </script>
|
也就是创建方法然后在方法中对message进行处理,分析一下this.message=this.message.split(“”).reverse().join(“”)
先用split拆分成数组再逆转,最后用join拼接成字符串。
输入事件
1 2 3 4 5 6 7 8 9 10 11 12
| <div id="app"> <div>{{message}}</div> <input type="text" v-model="message"> </div> <script> var app = new Vue({ el: '#app', data:{ message:"hello xgfm" } }) </script>
|
使用v-model将message和div中显示的值绑定在一起
Vue组件初体验
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <div id="app"> <xgfm></xgfm> </div> <script> Vue.component('xgfm',{ template:'<h1>hello xgfm</h1>' }) var app = new Vue({ el: '#app', data:{ message:"hello xgfm" } }) </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div id="app"> <xgfm v-bind:name="hello"></xgfm> </div> <script> Vue.component('xgfm',{ props:['name'], template:'<h1>hello {{name}}</h1>' }) var app = new Vue({ el: '#app', data:{ message:"hello xgfm", hello: 'xgfm!!' } })
|
目前的理解就是将标签的展示和数据分离出来,可以重复使用
一个组件本质上是一个拥有预定义选项的一个 Vue 实例
Vue实例
1 2 3 4 5 6 7 8 9 10
| <div id="app"> <div>{{a}}</div> </div> <script> var data={a:1} var app = new Vue({ el: '#app', data:data }) </script>
|
既可以访问data的a,也可以访问app中的a。这两个数据是双向绑定的。后来加入的属性是不会更新的。
如果使用了冻结泽不会影响。
Vue 实例还暴露了一些有用的实例 property 与方法。它们都有前缀 $
,以便与用户定义的 property 区分开来。
会输出两个true
1 2
| console.log(app.$el==document.getElementById("app")) console.log(app.$data==data)
|
created
钩子可以用来在一个实例被创建之后执行代码.
也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted
、updated
和 destroyed
。生命周期钩子的 this
上下文指向调用它的 Vue 实例。
1 2 3 4 5 6 7
| var app = new Vue({ el: '#app', data:data, created(){ console.log("create") } })
|
通过这样来使得可以在vue的生命周期的某个时间段进行操作,例如数据初始化和数据的销毁操作。
Vue模板语法
这种符号不可以用在html标签之中,需要使用v-bind如下:
1 2
| <button v-bind:disabled="!enableBtn">按钮</button>
|
需要直接显示字符串则使用v-html=
在{}中可以直接使用简单的表达式
1
| <div >{{num>101?'good':num}}</div>
|
如果在html标签中
1
| <a href="https://xgfm737.github.io">星光浮梦</a>
|
要将该超链接地址写入data之中,可以使用v-bind
1
| <a v-bind:href="mylink">星光浮梦</a>
|
总结
v-once
指令,定义它的元素或组件只会渲染一次,包括元素或者组件的所有字节点。首次渲染后,不再随着数据的改变而重新渲染
v-html
指令,可以输出真正的HTML语句
v-bind
指令,让语法能够作用在 HTML 标签上,可以使用:
进行简化代替
v-on
指令,用于绑定事件,可以用@
进行简化代替
Vue计算属性
例如:
1 2
| <div>{{message}}</div> <div>{{message.split("").reverse().join("")}}</div>
|
两者是反转的字符串,但这样操作过于不便利,所以这时可以使用计算属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Vue.component('xgfm',{ props:['name'], template:'<h1>hello {{name}}</h1>' }) var app = new Vue({ el: '#app', data:{ message:"hello xgfm", hello: 'xgfm!!' }, computed:{ reverseMessage(){ return this.message.split("").reverse().join('') } } })
|
添加computed,然后在引用中直接进行调用即可。
1
| <div>{{reverseMessage}}</div>
|
也可以在方法中编写相同的reverseMessage,但是需要在这之后添加()
语句区别如下:
1 2
| <div>{{reverseMessage}}</div> <div>{{reverseMessage()}}</div>
|
方法和计算属性的区别在于方法是每次运行都调用一次方法进行计算,而计算属性存在缓存,当message没有发生变化,不会进行下一步的计算,效率相对而言更加高一些。
完整的计算属性使用如下:
1 2 3 4 5 6 7 8 9 10
| computed:{ reverseMessage:{ get(){ return this.message.split("").reverse().join('') } } }
|
还有set方法如下:
1 2 3 4 5 6 7 8
| reverseMessage:{ get(){ return this.message.split("").reverse().join('') }, set(newVal){ console.log("set方法"+newVal) } }
|
即进行赋值等操作时都会执行一次set方法。
一般情况下只是用get方法,并且省略成最上面的样式即可了。
Vue侦听器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <div id="app"> <div>{{fullName}}</div> </div> <script> var app = new Vue({ el: '#app', data:{ firstName:'zhang', lastName:'san', fullName:'zhang san' }, watch:{ firstName(val){ this.fullName=val+" "+this.lastName }, lastName(val){ this.fullName=this.fullName+" "+val } } }) </script>
|
一般来说侦听器不要随意用,实际中一些复杂的异步才会使用watch侦听器,此处例子使用上面所讲述的计算属性(co mputed)会更好一些。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <div id="app"> <div>{{fullName}}</div> </div> <script> var app = new Vue({ el: '#app', data:{ firstName:'zhang', lastName:'san' }, computed:{ fullName(){ return this.firstName+' '+this.lastName } } }) </script>
|
Class绑定
1 2 3 4 5 6 7 8 9 10 11 12
| <div id="app"> <div v-bind:class="{mydiv:flag}">{{msg}}</div> </div> <script> var app = new Vue({ el: '#app', data:{ msg:'hello xgfm!!!', flag:true } }) </script>
|
其中mydiv是定义的css样式,flag为布尔类型,true则样式生效,false则样式不生效
多种样式共存
写法一
1 2 3 4 5 6 7 8 9 10 11 12 13
| <div id="app"> <div v-bind:class="{mydiv:flag,mydiv2:hasBorder}" class="mydiv1">{{msg}}</div> </div> <script> var app = new Vue({ el: '#app', data:{ msg:'hello xgfm!!!', flag:true, hasBorder:true } }) </script>
|
写法二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <div id="app"> <div v-bind:class="classObj" class="mydiv1">{{msg}}</div> </div> <script> var app = new Vue({ el: '#app', data:{ msg:'hello xgfm!!!', flag:true, hasBorder:true, classObj:{ mydiv:true, mydiv2:true } } }) </script>
|
写法三(使用最多的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <div id="app"> <div v-bind:class="classObj" class="mydiv1">{{msg}}</div> </div> <script> var app = new Vue({ el: '#app', data:{ msg:'hello xgfm!!!', flag:true, hasBorder:true }, computed:{ classObj(){ return{ mydiv: this.flag, mydiv2:this.hasBorder } } } }) </script>
|
使用选项卡切换也容易用到该方法。
写法四
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <div v-bind:class="[flag ? mydivClass:'',mydiv2Class]">{{msg}}</div> <script> var app = new Vue({ el: '#app', data:{ msg:'hello xgfm!!!', flag:true, hasBorder:true, mydivClass:'mydiv', mydiv2Class:'mydiv2' }, computed:{ classObj(){ return{ mydiv: this.flag, mydiv2:this.hasBorder } } } }) </script>
|
Style绑定
与Class绑定相似
1 2 3 4 5 6 7 8 9 10 11 12 13
| <div id="app"> <div v-bind:style="{color:fontColor,fontSize:fontSize+'px'}">{{msg}}</div> </div> <script> var app = new Vue({ el: '#app', data:{ msg:'hello xgfm', fontColor:'red', fontSize:30 } }) </script>
|
也可以在data数据中定义styleObj
1 2 3 4
| styleObj:{ color:'red', fontSize:'30px' }
|
使用如下div
1
| <div v-bind:style="styleObj">{{msg}}</div>
|
这里需要注意的是styleObj中的属性需要与css定义的样式、名称一致(-替换为驼峰命名法),并且fontsize更改为字符串,否则没有px也无法识别。
与class相类似的,这个也能使用obj数组
1
| <div v-bind:style="[styleObj,styleObj2]">{{msg}}</div>
|
多定义几个obj即可
Vue条件渲染
v-if指令:接受一个布尔类型的值,为true则显示出来,为false则隐藏
如果需要同时控制多个元素,需要添加template,该元素在渲染完成后将不存在。(会大量使用)
v-else指令:与v-if指令成对出现,其效果显而易见,如果if判断是false则else标签里的元素为出现,反之亦然。
v-else-if指令:也就是常见的elseif的作用,不再赘述。
也可以用于修改input下的文字,但默认情况下会出现元素复用,如果不想进行元素复用,则可以添加key来避免元素复用。(循环渲染时会频繁用到该技巧)
v-show指令用法也是如此,一般来说需要频繁显示隐藏,使用v-show更加合理,但是v-show不能添加到template之中,因为v-show是通过css样式对标签进行控制,而template在第一次渲染完成后会不存在,这就导致了v-show的display:none 的css样式根本无法添加到template中的元素上
最后附上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <div id="app"> <div v-if="isShow">Hello Vue!</div> <template v-if="isShow"> <p>hello xgfm</p> <div>xgfm hello</div> <span>xgfm737.github.io</span> </template> <div v-else>星光浮梦</div> 性别: <div v-if="gender==0">男</div> <div v-else-if="gender==1">女</div> <div v-else>未知</div>
<template v-if="loginType=='username'"> <label>用户名</label> <input type="text" placeholder="请输入用户名" key="username"> </template> <template v-else-if="loginType=='email'"> <label>用户名</label> <input type="text" placeholder="请输入用户邮箱地址" key="email"> </template>
<hr>
<div v-show="!isHide">hello v-show</div>
</div> <script> var app = new Vue({ el: '#app', data:{ isShow:false, gender:0, loginType:'username', isHide:false }
}) </script> </body> </html>
|
Vue列表渲染
和JSP中的for循环相类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <div id="app"> <table border="1"> <tr> <td>下标</td> <td>书名</td> <td>作者</td> </tr> <tr v-for="(book,index) in books"> <td>{{index}}</td> <td>{{book.name}}</td> <td>{{book.author}}</td> </tr> </table> </div> <script> var app = new Vue({ el: '#app', data:{ books:[ { name:'三国演义', author:'罗贯中' },{ name:'红楼梦', author:'曹雪芹' },{ name:'水浒传', author:'施耐庵' },{ name:'西游记', author:'吴承恩' } ] } }) </script>
|
1 2 3
| <div v-for="(s,kmm,index) in site" v-bind:key="index"> {{s}}---{{k}} </div>
|
可以这样直接循环进行输出,但是如果这样的话,有时需要添加上key避免复用
数组变更
Vue 将被侦听的数组的变更方法进行了包裹,所以这些方法也将会触发视图更新。
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
如果使用之前js中的方法对数组进行修改,是无法触发视图更新的
替换数组
变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如 filter()
、concat()
和 slice()
。它们不会变更原始数组,而总是返回一个新数组。
1 2 3
| app.books.concat({name:'11',author:'1'})
app.books=app.books.concat({name:'11',author:'1'})
|
从第0个开始删除1个并添加一组数据(松哥推荐)
1
| app.books.splice(0,1,{name:"1",author:"1"})
|
官方推荐的
1
| vue.set(vm.items,idnex0fItem,newValue)
|
VUE不能检测对象属性的添加或删除,如果是已经创建的实例中的嵌套对象可以使用该方法vue.set(vm.items,idnex0fItem,newValue)
事件处理
v-on
简单的自增代码
1 2 3 4 5 6 7 8 9 10 11 12
| <div id="app"> <div>{{counter}}</div> <input type="button" value="自增" v-on:click="counter++"> </div> <script> var app = new Vue({ el: '#app', data:{ counter:0 } }) </script>
|
也可以绑定方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| <script> var app = new Vue({ el: '#app', data:{ counter:0 }, methods:{ increment(){ this.counter++ } } }) </script>
|
事件修饰符
.stop
.prevent
.capture
.self
.once
.passive
按键码
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
如果没有别名则需要输入keycode
表单输入绑定
text和textarea
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <div id="app"> <div>{{counter}}</div> <input type="text" v-model="message"> <div>{{message}}</div> <hr> <textarea v-model="textarea" cols="30" rows="10"></textarea> <div>{{textarea}}</div> </div> <script> var app = new Vue({ el: '#app', data:{ message:'', textarea:'' } }) </script>
|
如果想让多行文本存在换行则要添加样式:
1
| <p style="white-space: preline;">{{message}}</p>
|
复选框
单个
1 2
| <input type="checkbox" v-model="isRead"> <div>{{isRead}}</div>
|
isRead为布尔类型
多个
1 2 3 4
| <input type="checkbox" value="足球" v-model="favorties">足球 <input type="checkbox" value="篮球" v-model="favorties">篮球 <input type="checkbox" value="羽毛球" v-model="favorties">羽毛球 <div>{{favorties}}</div>
|
favorties数组
单选框
1 2
| 性别:<input type="radio" value="男" v-model="gender">男<input type="radio" value="女" v-model="gender">女 <div>{{gender}}</div>
|
下拉框
1 2 3 4 5 6 7 8
| <select v-model="edu"> <option value="小学">小学</option> <option value="初中">初中</option> <option value="高中">高中</option> <option value="本科">本科</option> <option value="大专">大专</option> </select> <div>{{edu}}</div>
|
1 2 3 4 5 6
| <select v-model="favorties" multiple> <option value="足球">足球</option> <option value="篮球">篮球</option> <option value="羽毛球">羽毛球</option> </select> <div>{{favorties}}</div>
|
1 2 3 4
| <select v-model="favorties" multiple> <option v-for="(f,index) in fs" v-bind:key="index" v-bind:value="f">{{f}}</option> </select> <div>{{favorties}}</div>
|
修饰符
在默认情况下,v-model在每次 input事件触发后将输入框的值与数据进行同步
你可以添加 lazy修饰符,从而转为在 change 事件之后进行同步
1 2
| <input type="text" v-model.lazy="message"> <div>{{message}}</div>
|
.number
如果想自动将用户的输入值转为数值类型,可以给 v-model添加 number修饰符
.trim
如果要自动过滤用户输入的首尾空白字符,可以给v-model 添加 trim修饰符
其他
有时候可能想把值绑定到Vue实例的一个动态属性上,这时候可以使用v-bind实现,并且这个属性的值可以不是字符串
1 2
| <input type="checkbox" true-value="yes" false-value="no" v-model="toggle"> <div>{{toggle}}</div>
|
Vue组件基础
组件的复用
组件很多情况下会复用,如果不定义为方法进行,会导致各个复用的情况中一起发生变化(新版已经修改为直接报错)在组件中定义data需要定义为一个方法,通过return来赋值。
1 2 3 4 5 6 7 8
| Vue.component('xgfm',{ data() { return{ counter:0 } }, template:'<button v-on:click="counter++">hello {{counter}}</button>' })
|
此处定义是全局定义
通过Prop向子组件传递数据
1 2 3 4 5 6 7 8 9
| Vue.component('myblog',{ props:['title','date','author'], template: '<div>'+ '<div>{{title}}</div>'+ '<div>{{date}}</div>'+ '<div>{{author}}</div>' +'</div>' } )
|
组件传参的实用
1 2 3 4 5 6 7 8 9
| Vue.component('myblog',{ props:['title','date','author'], template: '<div>'+ '<div>{{title}}</div>'+ '<div>{{date}}</div>'+ '<div>{{author}}</div>' +'</div>' } )
|
1
| <myblog v-for="(blog,index) in blogs" :title="blog.title" :date="blog.date" :author="blog.author" :key="index"></myblog>
|
单个根元素
可以将模板的内容包裹在一个父元素内,来修复这个问题
监听子组件
也可以绑定子组件
1 2 3 4 5 6 7 8 9
| Vue.component('myblog',{ props:['title','date','author'], template: '<div>'+ '<div>{{title}}</div>'+ '<div>{{date}}</div>'+ '<div>{{author}}</div>'+ '<button @click="$emit(\'sayhello\')">click</button>' +'</div>' }
|
1
| <myblog @sayhello="hello" v-for="(blog,index) in blogs" :title="blog.title" :date="blog.date" :author="blog.author" :key="index"></myblog>
|
1 2 3 4 5
| methods:{ hello(){ console.log("hello vue") } },
|
在使用该组件时,给定义的子组件附上方法即可
也可以进行传参
1
| '<button @click="$emit(\'sayhello\',title)">click</button>'
|
1 2 3 4 5
| methods:{ hello(val){ console.log("hello "+val+"!") } }
|
使用$emit的第二个参数来提供这个值
插槽
在组件中提前定义好一个占位符(vue中使用的是slot)
slot展示的是自定义组件标签中的内容,并且slot可以插入多个,进行取名加以区分
1 2 3
| <myblog ...> <div style="color:red">星光浮梦</div> </myblog>
|
1 2 3 4 5 6 7 8
| Vue.component('myblog',{ props:['title','date','author'], template: ...+ '<slot></slot>' +... } )
|
重点在于slot
动态组件
在下面的示例中,currentTabComponent
可以包括
1
| <div id='app'><component v-bind:is="currentTabComponent"></component></div>
|
1 2 3 4 5 6
| var app = new Vue({ el: '#app', data:{ currentTabComponent:'xgfm' } })
|
1 2 3 4 5 6 7 8 9
| Vue.component('xgfm',{ data() { return{ counter:0 } }, props: ['title'], template:'<div><button v-on:click="counter++">hello {{counter}}</button><div>{{title}}</div></div>' })
|
这样这条component就会变成vue组件xgfm,与下述等价
完结
总的来说还是快速入门,并没有多么学透,只是知道了一些常用的功能该如何使用。剩下等做项目的时候在慢慢补充,基础知识就先这样