vue指令和事件绑定
安装npm
简单的说,npm就是JavaScript的包管理工具。类似Java语法中的maven,gradle,python中的pip。
去nodejs官网下载nodejs傻瓜式安装即可,默认会安装npm。但是这个npm可能不是最新的,更新:npm install npm@latest -g
使用步骤:
- 初始化:
npm init
- 安装包:
npm install jquery@2.0.1 --save --save
或者npm install jquery --save
- 卸载包:
npm uninstall jquery --save
vue的MVVM模式
MVP
- Model 层:模型层
- Presenter 层:呈现层(业务逻辑控制层)
- View 层:视图层(DOM 展示)
过程:视图层(V)发出一个事件交给控制器(P 呈现层),控制器调用 Ajax 去模型层(M)获取数据 ; 或者直接去视图层(V)进行DOM 操作。控制器(P 呈现层)是核心,是模型层(M)和 视图层(V) 的中转站,其中大部分代码在进行 DOM 操作
之前的开发是面向 DOM 开发,其中模型层(M)比较边缘(仅仅从M取点数据)
MVVM
MVVM分为三个部分:分别是M(Model,模型层 ),V(View,视图层),VM(ViewModel,V与M连接的桥梁,也可以看作为控制器)
- M:模型层,主要负责业务数据相关,在vue中模型层可以先简单地看作是vue对象的data属性里定义的变量值
- V:视图层,顾名思义,负责视图相关,细分下来就是html+css层;
- VM:V与M沟通的桥梁,负责监听M或者V的修改,是实现MVVM双向绑定的要点;
MVVM支持双向绑定,意思就是当M层数据进行修改时,VM层会监测到变化,并且通知V层进行相应的修改,反之修改V层则会通知M层数据进行修改,以此也实现了视图与模型层的相互解耦;
理解MVVM双向绑定是开始vue的第一步,其次编写vue代码是面向数据(模型层)开发,这是和以前单纯地写jquery代码很大的一点不同
指令
官网这样描述指令:指令 (Directives) 是带有 v- 前缀的特殊特性。指令特性的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
其实说的更明白一点,指令系统可看作是一种声明式编程,原先写jquery代码的时候都是写js代码去页面 添加,删除DOM等,修改DOM的属性和class都需要拿到这个DOM,然后调用prop,addClass这一系列方法命令页面做改动。但是vue不一样,它的思想是把我们想要显示或隐藏的DOM写出来,DOM可能需要(也可能不需要)的属性等都写出来,也就是说把 我们 期望的 都 声明在html文档中,根据model的改变去控制DOM,也就是说页面需要的DOM在刚开始就已经全部写在html文档中了,几乎不存在后续在添加删除DOM,只是需要面向数据编程即可,极大地解放了双手,哈哈!
v-if 操作
v-if 的作用是控制DOM是否显示
官网示例:
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
v-if=‘str'
表示是否显示取决于vue对象的data属性中定义的str变量的真假与否
<div id='app'>
<h3 v-if="str">hello</h3>
<h3 v-else></h3>
<h3 v-if="love === hzw">海贼王</h3>
<h3 v-else-if="love === hyrz">火影忍者</h3>
<h3 v-else>微动漫</h3>
</div>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app', // 表示id 为app 的标签使用vue的语法
data: {
str: true,
love:hzw,
}
})
</script>
v-show
v-show也是控制dom显示与否的,v-show 没有v-if的多个判断功能,而且v-show是把dom渲染到文档中,只是加了display:none
而已。
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
v-bind
v-bind用于绑定DOM 属性,即通过更改model层的data达到更改DOM属性的效果,而不是一开始把DOM属性写死。其中v-bind 绑定的属性中属class比较特殊
动态绑定普通属性
<div id='app'>
<h3 v-bind:title="t">hello</h3>
<h3 :title="t">hello</h3>
</div>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app', // 表示id 为app 的标签使用vue的语法
data: {
t:'sb',
}
})
</script>
绑定class
通过绑定class能动态切换已经在style定义好的class
字典形式
<div id='app'>
<h3 v-bind:class="{red:is_red, blue: is_blue}">hello</h3>
<h3 :title="t">hello</h3>
</div>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app', // 表示id 为app 的标签使用vue的语法
data: {
is_red: true,
is_blue: true
}
})
</script>
渲染的结果
数组
<div id='app'>
<h3 v-bind:class="[red, blue]">hello</h3>
<h3 :title="t">hello</h3>
</div>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app', // 表示id 为app 的标签使用vue的语法
data: {
red: 'aaa',
blue: 'bbb'
}
})
</script>
数组套字典
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
v-for
循环,又叫列表渲染,在需要显示多个的标签上加这个。
循环单个对象
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
new Vue({
el: '#v-for-object',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})
结果
值得注意的是vue默认循环的是values,和py默认循环keys不一样
也可以这样
<div id='app'>
<ul id="v-for-object" class="demo">
<li v-for="(value,key) in object">
{{ value }}----- {{ key }}
</li>
</ul>
</div>
结果为
循环多个对象的数组
<div id='app'>
<ul class="demo">
<li v-for="(item,key) in objs">
{{ item }}----- {{ key }}
</li>
</ul>
<ul class="demo">
<li v-for="item in objs">
{{ item }}
</li>
</ul>
</div>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
objs: [{name: 'John',age: 30},
{name: 'Jack',age: 20},
{name: 'lisz',age: 30}]
}
})
</script>
结果为
v-on
v-on表示事件监听
<div id='app'>
{{ count }}
<button v-on:click="count += 1">点我加1</button>
<button v-on:click="sub">点我减1</button>
</div>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
count:1
},
methods: {
sub(){
this.count -= 1
}
}
})
</script>
v-bind可以简写为:、v-on: 可以简写@
计算属性computed
虽然{{}}
支持写复杂的表达式逻辑,但是不推荐这么做,推荐用计算属性计算得出
<div id='app'>
<!-- reverseStr 当作是data的变量一样调用 -->
{{ reverseStr }}
</div>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
str:'hello'
},
computed:{
reverseStr(){
return this.str + 'world'
}
}
})
</script>
<div id='app'>
{{ str }}
<button @click="change">点我</button>
</div>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
str:'hello'
},
methods:{
change(){
this.changeStr = 'haha'
}
},
computed:{
changeStr:{
get:function () {
return this.str
},
set: function (new_value) {
this.str = new_value;
}
}
}
}
)
</script>
因为计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要msg还没有发生变化,多次访问currentMsg计算属性会立刻返回之前计算的结果,而不比再次执行函数。同样的。每当触发重新渲染时,调用方法将总会执行函数。一旦计算属性中的值发生变化,那么计算属性的值也就会立马发生改变(实时监听计算属性表示式的值)
v-model
v-model很好地体现了vue双向绑定的理念。
单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新。有单向绑定,就有双向绑定。
如果用户更新了View,Model的数据也自动被更新了,这种情况就是双向绑定。
什么情况下用户可以更新View呢?填写表单就是一个最直接的例子。当用户填写表单时,View的状态就被更新了,如果此时MVVM框架可以自动更新Model的状态,那就相当于我们把Model和View做了双向绑定。
<div id='app'>
<input v-model="str">
{{ str }}
</div>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
str:'hello'
},
}
)
</script>
双向数据绑定=单向数据绑定+UI事件监听
参考:https://cn.vuejs.org/v2/guide/forms.html
v-html
<div id='app'>
<div v-html="str"></div>
</div>
<script src="./vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
str:'<p>hello</p>'
},
}
)
</script>
轮播
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
ul li {
list-style: none;
float: left;
width: 30px;
height: 30px;
background-color: #5cb85c;
margin-right: 10px;
}
.red {
background-color: red;
}
</style>
</head>
<body>
<div id='other'>
<h3 v-if="str">hello</h3>
<img :src="src" @mouseenter="stop" @mouseleave="start">
<ul>
<li v-for="(item,i) in imgs" @click="changeImg(i)" :class="{red:item.show}">
{{ i}}
</li>
</ul>
<button @click="prePage">上一页</button>
<button @click="nextPage">下一页</button>
</div>
<script src="./vue.js"></script>
<script>
var other = new Vue({
el:'#other',
data:{
imgs:[{name:'1.jpg',show:false},
{name:'2.jpg',show:false},
{name:'3.jpg',show:false},
{name:'4.jpg',show:false},
{name:'5.jpg',show:false}],
src:'1.jpg',
index:0,
cl: null
},
methods:{
changeImg(i){
this.src = this.imgs[i].name;
},
nextPage(){
cur = this.imgs.indexOf(this.src)
cur += 1;
cur = cur % this.imgs.length
this.src = this.imgs[cur].name;
this.imgs[cur].show = true;
for (let i=0;i<other.imgs.length;i++){
if (cur != i){
other.imgs[i].show = false;
}
}
},
prePage(){
cur = this.imgs.indexOf(this.src)
cur -= 1;
if (cur < 0){
cur = 4
}
this.src = this.imgs[cur].name;
for (let i=0;i<other.imgs.length;i++){
if (cur != i){
other.imgs[i].show = false;
}
}
},
stop(){
clearInterval(this.cl);
},
start(){
this.cl = setInterval(function(){
other.index += 1;
if (other.index == 5){
other.index = 0
}
other.src = other.imgs[other.index].name;
other.imgs[other.index].show = true;
for (let i=0;i<other.imgs.length;i++){
if (other.index != i){
other.imgs[i].show = false;
}
}
}, 1000);
}
},
created(){
this.cl = setInterval(function(){
other.index += 1;
if (other.index == 5){
other.index = 0
}
other.src = other.imgs[other.index].name;
other.imgs[other.index].show = true;
for (let i=0;i<other.imgs.length;i++){
if (other.index != i){
other.imgs[i].show = false;
}
}
}, 1000);
}
})
</script>
</body>
</html>