什么是Vue
一套构建用户界面的渐进式框架,那么什么是渐进式?
一层一层,一步步来做事情,剥洋葱的形式来,例如一开始只需要用到声明式渲染,而后面随着业务变得越来越复杂会用到Vue的其他部分,一层层向外拓展,相当于一种组合的思想。
安装
直接使用<script>标签引入
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
通过npm安装,安装在了node_modules里面
npm i vue
实现Hello World
- View层,使用类HTML,用到了{{ }}这个语法糖,将要显示的视图内容写在这个双大括号里面
<div id="app">{{msg}}</div>
- 逻辑层,写入处理逻辑和展示的数据
const app = new Vue({
el:'#app',//建立视图层和逻辑层的联系
data:{
msg:'hello world'
}
})
MVVM框架
刚刚提到了View层和逻辑层(model层),那么什么是MVVM框架呢?
MVVM框架分为三层,也就是View层,Model层,ViewModel层,View层就是我们写的DOM元素,也就是展现出来的视图,Model层是我们写入的JavaScript对象,也就是一些数据处理的逻辑在里面,那么ViewModel这一层其实上就是Vue,Vue帮我们做了一个视图和数据的双向绑定,当我们去修改数据的时候,视图也会发生改变,同样的,当视图发生改变的时候数据也发生改变了,这是Vue内部去帮我们实现的。这也就决定了,我们以后都是去操作数据,通过数据的变更去驱动视图的变更。
基础语法
v-bind属性插值
<div id="app">
{{msg}}
<div v-bind:test-id="testId"></div>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
msg:'hello world',
testId:1
}
})
</script>
其中v-bind:test-id="testId"可以简写成:test-id="testId"
注意:无论是{{}}文本插值还是v-bind属性插值,都支持js表达式
v-on事件处理
<div id="app">
{{msg}}
<button v-on:click="handleClick(1, $event)">click</button>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
msg:'hello world'
},
methods:{
handleClick(type, e){
console.log(type, e);
}
}
})
</script>
其中v-on:click="handleClick"可以简写成@click="handleClick"
并且函数支持调用,在v-on:click="handleClick(1)"中的参数可以在函数里面接收到,并且还可以通过$event获取到当前的事件对象。
修饰符:
- .stop - 调用 event.stopPropagation(),可以阻止当前事件向祖辈元素的冒泡传递。
- .prevent - 调用 event.preventDefault(),取消事件的默认动作。
- .capture - 添加事件侦听器时使用 capture 模式。
- .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
- .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
- .native - 监听组件根元素的原生事件。
- .once - 只触发一次回调。
- .left - (2.2.0) 只当点击鼠标左键时触发。
- .right - (2.2.0) 只当点击鼠标右键时触发。
- .middle - (2.2.0) 只当点击鼠标中键时触发。
- .passive - (2.3.0) 以 { passive: true } 模式添加侦听器
计算属性computed
通过命名表达程序的意图,和方法的区别:(1)在调用的时候不需要加括号(2)计算属性是有缓存的,避免了重复计算,在调用方法时每次调用都会计算一次,而计算属性只有在依赖的属性发生变化时改变
计算属性的特点:
- 可读性
- 缓存
- 多对一,一个计算属性可以依赖多个关系
<div id="app">
{{ message }}
<p>调用计算属性{{reverseMsg + reverseMsg}}</p>
<p>调用方法{{handleClick()}}</p>
<button type="button" @click="handleClick()">click</button>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!',
count:1
},
computed: {
reverseMsg() {
console.log('调用计算属性');
return this.message.split('').reverse().join('') + this.count;
}
},
methods:{
handleClick(){
console.log('调用方法');
return this.message.split('').reverse().join('') + this.count;
}
}
})
</script>
上面的代码调用两次计算属性reverseMsg,但控制台只打印了一次输出,因为有缓存,而方法每次调用的时候都会在控制台打印消息
Watch
Vue提供的侦听数据的功能,用于在数据发生变化的时候驱动特定的操作,vue官方文档解释当需要在数据变化时执行异步或开销较大的操作时,推荐使用该方法。
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!',
count:1
},
methods: {
handleClick() {
this.count++;
}
},
watch: {
count(newValue, oldValue) {//当count发生改变的时候,执行下面的操作,可以获取改变前后的值
console.log('oldValue', oldValue);
console.log('newValue', newValue);
console.log('count is changed');
// 在这里可以做一些一部操作请求后端。
}
}
})
当有多个属性依赖某一个属性时(例如foo和bar都依赖于count),也可以用watch
watch: {
count(newValue, oldValue) {
console.log('oldValue', oldValue);
console.log('newValue', newValue);
console.log('count is changed');
this.foo = 'foo' + newValue;
this.bar = 'bar' + newValue;
}
}
对象形式的写法,写在handler函数中
watch:{
count:{
handler(newValue, oldValue){
console.log('oldValue', oldValue);
console.log('newValue', newValue);
console.log('count is changed');
this.foo = 'foo' + newValue;
this.bar = 'bar' + newValue;
},
immediate:true // 将立即以表达式的当前值触发回调
}
}
对象的侦听及深度侦听(deep),如果不是深度侦听,只能侦听到整个对象的改变,对于对象里面某个属性的改变没法侦听到。
const app = new Vue({
el:'#app',
data:{
user:{
name:'hjj',
age:18
}
},
watch:{
user:{
handler(newVal, oldVal){
console.log(newVal);
},
deep:true // 深度侦听,当对象里面的某个属性发生改变时也能侦听到
}
// 也可以侦听对象的某一个属性
'user.name':{
handler(newVal, oldVal){
console.log('user.name is changed');
console.log(newVal);
}
}
}
})
条件渲染
- v-if
- v-else-if
- v-else
<div id="app">
<div v-if="age<18">未成年</div>
<div v-else-if="age=18">18岁</div>
<div v-else>成年了</div>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
age:18
}
})
</script>
v-if vs v-show 如果是v-if,当不满足条件的时候都不会渲染;而v-show是通过style样式去控制的
列表渲染
数组的列表渲染
<div id="app">
<ul>
<li v-for="(item, index) in users">{{index}} -- {{item.name}} -- {{item.age}}</li>
</ul>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
users:[
{
id:1,
name:'hhh',
age:18
},
{
id:2,
name:'jjj',
age:30
}
]
}
})
</script>
对象的列表渲染
<div id="app">
<ul>
<li v-for="(val, key, index) in userInfo">{{index}} -- {{key}} -- {{val.name}} -- {{val.age}}</li>
</ul>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
userInfo:{
1:{
id:1,
name:'hhh',
age:18
},
2:{
id:2,
name:'jjj',
age:30
}
}
}
})
</script>
class & style
class
<style>
.red{
color: red;
}
.fontSize{
font-size: 60px;
}
</style>
<div id="app">
{{msg}}
<div :class="classes">foo</div>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
msg:'hello Vue',
count:1,
// 1.对象形式
// classes:{
// red:false
// },
// 2.数组形式
// classes:['red']
// 3.联合使用
// classes:['red', {fontSize:true}]
},
// 4.计算属性
computed: {
classes() {
return ['red',
{
fontSize:this.count == 1
}
]
}
},
})
</script>
style
<div id="app">
{{msg}}
<div :style="styleInfo">foo</div>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
msg:'hello Vue',
count:1,
styleInfo:{
color:"blue",
fontSize:"100px"
}
}
})
</script>
表单输入绑定
v-model
<div id="app">
<input v-model="inputVal"/>{{inputVal}}
</div>
<script>
const app = new Vue({
el:'#app',
data:{
inputVal:''
}
})
</script>