【Vue】3 - 指令

1、指令 - 用来操作dom的

dom元素的行间属性,必须以v-开头,而且都是key /value的形式,value均为变量

1. v-model

v-model - 实现双向数据绑定,常用在input 或组件上

  1. 一般表单元素如input都要加v-model,且会忽略掉value 属性,selected,checked 都没有意义了
  2. v-model 作用:将数据帮到视图上,视图修改后会影响数据的变化

2. v-text / v-html

  1. 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。

  1. v-html ='<div>111</div>' – 把html字符当作html渲染,一定时可以信任的html

3. v-once/ v-focus

  1. v-once只绑定一次,当数据再次发生变化,也不会导致页面刷新
  2. v-focus

4. v-for

v-for数组:v-for = '(item,index) in arr' , 对象:v-for = '(value,key,index) in obj' --循环数组,对象,字符串或数字

  1. 要循环谁就在谁的身上加 v-for 属性
  2. 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里

  1. methods 和 data 上的数据会全部放到vm上,而且名字不能冲突,冲突会报错
  2. 不要随便用箭头函数,有this的问题,箭头函数没有this ,或向上找 this 指向 window
  3. 如果不传递参数,就不要写(),会自动传入事件源对象,如果写括号要手动传入$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

  1. 在html里使用变量,要先在data里定义(初始化), 如果data里没有定义,直接在页面里使用a {{a}},会像如下报错;
    在这里插入图片描述
  2. 如果在data里定义了 a:{} 一个空对象,里面没写属性,直接在html用属性{{a.name}}是不会报错的。但是name属性并不能响应式变化,vm.a.name=100 给name赋值,页面并不会响应变化;因为name 没有setter 和 getter

vue会循环data中的数据(数据劫持),依次给属性的增加getter 和 setter,有他们才能让a双向绑定,响应式变化;比如这里会给给一个getter 和 setter如下图:
在这里插入图片描述

  1. 使用变量时先要初始化,否则新加的属性不会导致页面刷新
    data里定义了 a:{ name: '' } 这样name就有setter 和 getter了
    在这里插入图片描述
  2. vm.$set()也可以用这个方法,可以给对象加一些新的属性,且属性是响应式的; vm.$set() = Vue.set()
vm.$set(vm.a,'school',1)   //给data 里的vm.a 添加属性school,值是1
  1. 如果要加很多个属性,可以替换原对象
vm.a = {school:'1',age'12'}
  1. vue监控的原理是一个个循环然后加上getter 和 setter

关于数组:

  1. vue改变数组中的某一项,是监控不到的,因为没法给每一项加getter 和 setter。
  2. =也不能使用改变数组长度的方法
  3. 可以使用变异方法: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>,需注意:

  1. 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>
发布了57 篇原创文章 · 获赞 4 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Eva3288/article/details/104183174