文章目录
1、指令 - 用来操作dom的
dom元素的行间属性,必须以v-开头
,而且都是key /value的形式,value均为变量
1. v-model
v-model
- 实现双向数据绑定,常用在input 或组件上
- 一般表单元素如
input都要加v-model
,且会忽略掉value 属性,selected,checked 都没有意义了- v-model 作用:将数据帮到视图上,视图修改后会影响数据的变化
2. v-text / v-html
v-text= 'msg'
( 等价于 {{}} )–,将内容插入到页面上,防止{{}}出现再页面上,解决闪烁问题,
官方给出v-cloak也可以解决闪烁(块)问题:1.
<div id="app" v-cloak></div>
给含多个{{}}的块元素加属性v-cloak 2. 利用 属性选择器修改样式[v-cloak]{display: none;}
现在不咋用了
{{}}有个缺点:会闪一下{{}},代码从上到下执行,执行到{{}}时,还没执行vue.js所以识别不出{{}}。
js文件要放下面,如果放上面走js时dom会停止渲染。所以要先渲染html 然后再走js。
v-html ='<div>111</div>'
– 把html字符当作html渲染,一定时可以信任的html
3. v-once/ v-focus
v-once
– 只绑定一次,当数据再次发生变化,也不会导致页面刷新v-focus
–
4. v-for
v-for
数组:v-for = '(item,index) in arr'
, 对象:v-for = '(value,key,index) in obj'
--循环数组,对象,字符串或数字
- 要循环谁就在谁的身上加 v-for 属性
- v-for 会复用原有的结构,是在原来的基础上把新的内容加上去,不是重新渲染,更高效
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<!-- 要循环谁就在谁的身上加 v-for 属性 -->
<li v-for='item of fruits1'>{{item.name}}</li>
<hr>
<!-- 可以写in 也可以写of ,in = of,建议用in-->
<li v-for='(item,index) in fruits1'>{{item.name}}{{index+1}}</li>
<hr>
<!-- 二维数组 -->
<li v-for='(item,index) in fruits2'>{{index+1}}.{{item.name}}
<ul>
<li v-for='(item1,index1) in item.chandi'>{{index+1}}.{{index1+1}}{{item1}}</li>
</ul>
</li>
</ul>
<!-- 虽然没啥用,但是v-for除了循环数组,还可以循环字符串,数字,对象 -->
<!-- v-for = '(value,key,index) in obj' -->
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
fruits1:[ //一维数组
{name:'苹果'},
{name:'橙子'},
{name:'西瓜'}
],
fruits2:[ //二维维数组:数组里嵌套了数组
{name:'苹果',chandi:['山东','云南']},
{name:'橙子',chandi:['越南','广西']},
{name:'西瓜',chandi:['东北']}
]
}
})
// 以前做法:拼字符串然后innerHTML,这样操作dom 重渲染,性能很低
// vue提供的指令v-for就解决循环问题的
// v-for 会复用原有的结构,是在原来的基础上把新的内容加上去,不是重新渲染,更高效
</script>
</body>
</html>
5.v-on / @
v-on:事件名 = 'fn'
事件
function 也是数据的一种,放在data里是可以的.但常放到methods里
- methods 和 data 上的数据会全部放到vm上,而且名字不能冲突,冲突会报错
- 不要随便用箭头函数,有this的问题,箭头函数没有this ,或向上找 this 指向 window
- 如果不传递参数,就不要写(),会自动传入事件源对象,如果写括号要手动传入
$event
参数获取
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- 事件的指令 v-on:事件名 = 'fn' -->
<!-- v-on: === @ -->
<!-- fn 后面的() 有参数传才写,没有参数传的话不写()-->
<!-- fn()这样写会覆盖掉默认传递的事件源对象 为undefined -->
<!-- 如果不传递参数,就不要写(),会自动传入事件源对象,如果写括号要手动传入$event参数获取 -->
<!-- 传参的话,需要event,这样写 fn($event , 1) $是vue自带的 -->
<div id="app" v-on:mousedown='fn1' v-on:mouseleave='fn2($event,1)'>点击1</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({ //vm
el:'#app',
//methods 和 data 上的数据会全部放到vm上,而且名字不能冲突,冲突会报错,
// methods中的this指向的都是实例vm
data:{ //2.但为了好看 好维护,我们常在datal里放数据:字符串 数字 布尔 对象 数组等
fn1(){ //1.function 也是数据的一种,放在data里是可以的
console.log(event); //如果 v-on:mousedown='fn1' fn 后面没写()会自动传入event
}
},
methods:{ //3.把函数放到methods里,和放在data里一样
//fn 不可以被重新声明,会报错
fn2(a,b){ // 这是es6写法,正常写法是 fn:function(){alert(1)} 省略了: 和func
console.log(a); //这就是传入的事件源对象
console.log(b);
}
// 这里不要随便用箭头函数,有this的问题,箭头函数没有this ,或向上找 this 指向 window
}
})
</script>
</body>
</html>
6.自定义指令directives - 拖拽
如果html里使用指令的时候是,v-focus-aa=''
那在定义的时候要使用小驼峰:focusAa
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="shortcut icon" href="#" type="image/x-icon">
<style>
.div1{
position:absolute;
width:100px;
height:100px;
background: peru;
/* top:150px;
left:100px; */
}
</style>
</head>
<body>
<div id="app">
<button v-color='colorName'>变色</button>
<div v-drag class = 'div1'>拖拽</div>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
directives:{
/* 1.v-color 是自定义指令,定义的时候可以写v-color 也可以简写为color
2.color是一个方法,用来操作dom的,所以第一参数是指令所对应的元素 */
color(el,bindings){
console.log(bindings);
// {name: "color", rawName: "v-color", value: "red", expression: "colorName", modifiers: {…}, …}
el.style.background = bindings.value;
},
drag(el){ //v-drag没有属性值,所以没有第二个参数
el.onmousedown = function(e){ //鼠标按下的时候调用事件,使用 事件源对象e
let disX = e.pageX - el.offsetLeft ; //点击点距div左侧距离 = 点击点据页面左侧距离 - div距页面左侧距离
let disY = e.pageY - el.offsetTop ;
// 鼠标按下的时候,获取鼠标据div左侧 和 顶部的距离
document.onmousemove = function(e){
el.style.left = e.pageX - disX + 'px';
el.style.top = e.pageY - disY + 'px';
}
document.onmouseup = function(){ //鼠标抬起的时候,情况鼠标按下 和 移动时的事件
document.onmousedown = document.onmousemove = null ;
}
e.preventDefault(); //阻止默认事件
}
}
},
data:{
colorName:'red',
}
})
</script>
</body>
</html>
2、关于data中的数据类型:{} 或 []
响应式数据变化reativity
- 在html里使用变量,要先在data里定义(初始化), 如果data里没有定义,直接在页面里使用a
{{a}}
,会像如下报错;
- 如果在data里定义了
a:{}
一个空对象,里面没写属性,直接在html用属性{{a.name}}
是不会报错的。但是name属性并不能响应式变化,vm.a.name=100
给name赋值,页面并不会响应变化;因为name 没有setter 和 getter
vue会循环data中的数据(数据劫持),依次给属性的增加getter 和 setter,有他们才能让a双向绑定,响应式变化;比如这里会给给一个getter 和 setter如下图:
- 使用变量时先要初始化,否则新加的属性不会导致页面刷新
data里定义了a:{ name: '' }
这样name就有setter 和 getter了
vm.$set()
也可以用这个方法,可以给对象加一些新的属性,且属性是响应式的;vm.$set() = Vue.set()
vm.$set(vm.a,'school',1) //给data 里的vm.a 添加属性school,值是1
- 如果要加很多个属性,可以替换原对象
vm.a = {school:'1',age'12'}
- vue监控的原理是一个个循环然后加上getter 和 setter
关于数组:
- vue改变数组中的某一项,是监控不到的,因为没法给每一项加getter 和 setter。
- =也不能使用改变数组长度的方法
- 可以使用变异方法:push , pop , unshift , shift , sort , reverse , splice, 这些方法可以改变数组
let vm = new Vue({
el:'#app',
data:{
arr:[1,2,3,4]
}
})
vm.arr[0] = 5; //1.这是错误写法: 改变数组中的某一项,监控不到,因为没法给每一项加getter 和 setter
// vm.arr.length -=2; //2.错误写法,这也是无效的
// vm.arr.reverse(); // 用数组的变异方法改变原数组
//==变异方法==:push , pop , unshift , shift , sort , reverse , splice, 这些方法可以改变数组
vm.arr = vm.arr.map(item => item *= 2); //filter , map 等,对数组操作后返回新数组,再赋值给原数组
3. 事件补充及练习:todoList
之前的点击事件onclick
:<div onclick='fn()'>点击</div>
,需注意:
- onclick 的缺点:它调用的方法需要都是window上的(全局的)
如果fn定义在局部作用域,像如下,会报错(function(){ function fn(){ //fn函数写在这里,onclick事件找不到这个函数 alert(1) } })()
2.<div onclick='fn()'>点击</div>
这里的fn后面必须加()
, 因为onclick是一个函数,点击时让这个函数执行,函数里面是fn()的话onclick执行的时候如图1,fn() 也执行了,如果传fn就如图2没法执行<div onclick='fn()' id='btn'>点击</div> <script> function fn(){ alert(1) } console.log(btn.onclick); </script>
另外:
btn1.onclick = function(){ //这样写是给函数onclick 赋值一个新匿名函数,点击的时候直接执行这个匿名函数
alert(2)
}
console.log(btn.onclick);
todoList
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- vue中的键盘修饰符 modifiers -->
<!-- 修饰符: @keyup.13 或者 @keyup/enter 和下面的条件判断 event.keyCode ===13 一样 -->
<!-- 修饰符:也可以写keyup.a 等任何键盘来触发事件 keyup.a.ctrl 按ctrl+a键 -->
<input type="text" v-model='val' @keyup.enter = add>
<ul>
<li v-for='(item,index) in list'>
{{item}}
<button @click = 'remove(index)'>删除</button>
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
val:'',
list:[],
},
methods:{
add(){ //add后面不加括号,会有事件源对象传入
// event.keyCode === 13 处理dom细节,回车的时候,
if(event.keyCode === 13){ //若干按的是回车键再添加数据
this.list.unshift(this.val);
this.val='';
}
},
remove(i){
this.list = this.list.filter((item,index)=>{
return i !== index; //true的项留下来
})
}
}
})
</script>
</body>
</html>