Bootstrap

Vue学习笔记

Vue

初始vue

开发前的配置

1.官网下载vue的依赖安装包,有两个版本,开发版本和测试版本。在 实际开发中使用开发版本,在打包上传的时候使用测试版本。

2.在浏览器中安装其开发者工具插件

案例

<!DOCTYPE html>
<html lang="en">
<head>
    <title>初始vue</title>
    <!-- 引入Vue -->
    <script src="../js/vue.js" type="text/javascript"></script>
</head>
<body>
    <!-- 总结
    1.想让Vue工作就必须创建Vue的实例,且要传入一个配置对象
    2.root容器里的代码依然符合 html规范,只不过混入了一些特殊的Vue语法
    3.root里的代码被称为【Vue模板】
    4.Vue实例和容器是一一对应的
    5.真实开发中只有一个实例,并且会配合着组件一起使用
    6.{{xx}}里中的xx要写js表达式,且xx可以自动读取data里的属性
    7.一旦data里面的数据发生改变,那么模板中用到该数据的地方也会发生改变
    注意区分js表达式和js代码 
    js表达式:
      1. 一个表达式可以产生一个值,可以放在任何一个需要值的地方
                (1)a
                (2)a+b
     const =    (3)demo(1)
                 (4)x === y ? 'a':'b'
       js代码:
         for()
         if(){}
    -->
    <!-- 创建一个容器 -->
    <div id="root">
        <h1>hello {{name}} </h1>
    </div>
    <script type="text/javascript">
        // 设置为 false 以阻止 vue 在启动时生成生产提示
        Vue.config.productionTip = false
        //创建一个vue实例,并且将配置对象传入进去
         new Vue({
            el:'#root', //el用于指定当前vue为哪个容器服务,值通常为css选择器
            data:{
                name:'world'   //data用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象
            }
        })
    </script>
</body>
</html>

指令语法

<!DOCTYPE html>
<head>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 插值语法 -->
    <!-- 首先创建一个容器 -->
    <div id="root">
        <h1>插值语法</h1>
        <h2>你好,{{name}}</h2>
        <hr>

        <h1>指令语法</h1>
        <a v-bind:href="url">点我去百度</a>
        <a :href="url">点我去百度</a>
    </div>
   
    <!-- 创建一个vue对象 -->
    <script>
        Vue.config.productionTip = false  // 设置为 false 以阻止 vue 在启动时生成生产提示
        new Vue({
            el:'#root' ,  //#代表了id选择器,el用于指定当前vue为哪个容器服务,值为css的id选择器
            data:{
                name:'vue',
                url:'https://www.baidu.com/',
            }
        })
    </script>
总结

Vue模板的两大类:

  1. 插值语法
  • 功能:用于解析标签体内的内容
  • 写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性
  1. 指令语法
  • 功能:用于解析标签(包括:标签属性,标签体内容,绑定事件…)
  • 举例:v-bind:href = ‘xxx’ 或简写为:href = ‘xxx’ ,xxx同样要写js表达式。且可以直接读取到data中的所有属性
  • 备注:Vue中有很多的指令,且形式都是:v-??? 。

单向绑定与双向绑定

Vue中有两种数据绑定方式:

  1. 单项绑定(v-bind):数据只能从data流向页面
  2. 双向绑定(v-model): 数据不仅能从data流向页面,还可以从页面流向data。
    • 备注:
      1. 双向绑定一般都应用在表单类元素上(如:input,select等)
      2. v-model:value 可以简写为v-model,因为v-model默认收集的就是value的值。
  <!-- 创建一个容器 -->
    <div id="root">
        <!-- 正常写 -->
        <!-- 单向绑定:<input type="text" v-bind:value="name">
        双向绑定:<input type="text" v-model: value="name"> -->
        <!-- 简写 -->
        单向绑定:<input type="text" :value="name">
        双向绑定:<input type="text" v-model="name">
    </div>

    <!-- 创建一个vue实例 -->
    <script>
        new Vue({
            el:'#root' ,  //el用于指定当前vue为哪个容器服务
            data:{
                name:'vue'
            }
        })
    </script>
    

el的两种写法

  1. el:‘#root’,
  2. v.$mount(‘#root’)
    <div id="root">
      <h1> 你好,{{name}} </h1>
    </div>
    <script>
    const v = new Vue({
           // el:'#root', //第一中写法
            data:{
              name:'vue'
            }
        })
       v.$mount('#root')  //第二中写法,mount的意思有挂载,  这个方法不是实例变量所拥有的,而是构建方法Vue所拥有的
    </script>

data的两种写法

  1. data:{}
  2. data:function(){}
  3. 简写: data(){}
 <script>
new Vue({
        el:'#root',
        // data:{
        //     name:'vue'
        // }  //目前这种写法没什么问题
        // data:function(){
        //     return {
        //         name:'vue'
        //     }
        // }
        //简写 ,当以后需要使用组件的时候一定要用函数的形式,,这个
        data(){
            console.log(this)  //这个this返回的是Vue的实例变量,如果要用箭头函数写的换话this代表的是windos,后期影响会很大
            return{
                name:'vue'
            }
        }
    })
    </script>
总结

data与el的两种写法

  1. el有2种写法

    • new Vue时候配置el属性
    • 先创建Vue实例,随后再通过vm.$mount(‘#root’)指定el的值
  2. data的2中写法

    • 对象式

    • 函数式

      如何选择:目前那种写法都可以,以后学习到组件的时候,data必须使用函数式

  3. 一个重要的原则:

    由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了

MVVM模型

image-20230615230935336

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结

MVVM模型

  1. M:模型(Model):data中的数据
  2. V:视图(View):模板代码
  3. VM:视图模型(ViewModel):Vue实例

观察发现:

  1. data中所有 的属性,最后都出现在了vm身上
  2. vm身上所有的属性及Vue原型上所有的属性,在Vue模板中都可以直接使用
数据代理Object.defineProperty
   <script>
        let number = 18
        let persion = {
            name:'vue'
        }
        Object.defineProperty(persion,'age',{
            //填写配置
            // value:number,
            // enumerable:true,//控制属性是否可以被枚举
            // writable:true,  //控制属性是否可以被修改
            // configurable:true //控制属性是否可以被删除
            //当age被调用时候,就会执行此方法
            get(){
                return number;
            },
            //当age被赋值时候,调用set方法
            set(value){
               number = value;
            }
        })
        //总结,object.defineproperty()添加数据的安全性更高,操作性更强,可变性也强
        console.log(Object.keys(persion))
    </script>
数据代理小结:
  1. Vue中的数据代理:

    通过vm对象来代理data对象中属性的操作(读/写)

  2. Vue中数据代理的好处:

    更加方便的操作data中的数据

  3. 基本原理:

    通过Object.defineProperty()把data对象中所有属性添加到vm上。

    为每一个添加到vm上 的属性都指定一个getter/setter

    在getter/setter内部去操作(读/写)data中对应的属性

图解:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

事件处理

总结

事件的基本使用:

  1. 使用v-on:xxx 或@xxx绑定事件,其中xx是事件名
  2. 事件的回调需要配置在methods对象中,最终会在vm上
  3. methids中配置的函数,不要用箭头函数!否则this就不是vm了
  4. methids中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象
  5. @click=‘demo’ 和@click=‘demo($event)’ 效果一致,但后者可以传参
    <div id="root">
        <h1>你好,{{name}} </h1>
        <button v-on:click="showInfo">请点我</button>
        <!-- 简写 -->
        <button @click="showInfo2(66)">请点我</button>

    </div>
    <!-- 注意事项,模板里面用到的数据只能在vue实例中调用,对象里面是方法 -->
    <script>
        new Vue({
            el:'#root',
            data:{
                name:'刘先生'
            },
            methods:{
                showInfo(){
                    alert('同学你好')
                },
                showInfo2(a){
                    console.log(a)
                    alert('同学你好!')
                }
            }
        })
    </script>

事件处理的修饰符:

总结

Vue中的事件修饰符:

  1. prevent:阻止默认事件(常用)
  2. stop:阻止事件冒泡(常用)
  3. once:事件只触发一次(常用)
  4. capture:使用事件的捕获模式(先从外向内捕获,再从内向外冒泡,一般都是在冒泡的时候执行点击事件)
  5. self:只有event.target 是当前操作的元素时才触发事件
  6. passive:事件的默认行为立即执行,无需等待事件回调执行完毕
  7. 修饰符可以连续写
<body>
    <div id="root" @click.capture = 'showInfo2(1)'>
        <!-- prevent属性阻止默认事件 -->
        <!-- <a href="https://www.baidu.com/" @click.prevent = 'showInfo'> 点击跳着</a> -->
        <a  @click = 'showInfo(2)'> 点击跳着</a>
    </div>
    <script>
        new Vue({
            el:'#root',
            data:{
                name:'刘先生'
            },
            methods:{
                showInfo(a){
                    console.log(a)
                    alert('同学你好')
                },
                showInfo2(a){
                    console.log(a)
                    alert('同学你好!')
                }
            }
        })
    </script>
</body>

Vue常用按键别名

  1. Vue中常用的按键别名:

    回车 ======enter

    删除 ========delete

    退出=========esc

    空格=========spacwe

    换行=========tab

    上===========up

    下===========down

    左===========left

    右===========right

  2. vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)

  3. 系统修饰键(用法特殊):ctrl alt shift meta

    • 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
    • 配合keydown使用:正常触发
  4. 也可以使用keyCode去指定具体的按键 (不推荐)

  5. vue.config.keyCodes 自定义键名 = 键码,可以去定制按键别名

<body>
       <div id="root">
        <input type="text" placeholder="请输入" @keydown.enter="infor" >
       </div>
       <script>
        new Vue({
            el:'#root',
            methods:{
                infor(e){
                    console.log(e.target.value)
                }
            }
        })
       </script>
</body>

vue计算属性

  1. 定义:要用的属性不存在,要通过已有属性计算得来
  2. 原理:底层借助了Objcet.defineproperty()方法提供的getter和setter
  3. get函数什么时候执行?
    • 初次调用的时候会执行一次
    • 当依赖的属性发生改变时会被再次调用
  4. 优势:与methods实现相比,内部由缓存机制(复用)。效率更高,调试方便
  5. 备注:
    • 计算属性最终会出现在vm上,直接读取使用即可
    • 如果计算属性要被修改,那必须写set函数去响应修改,且setter中要引起计算所依赖的数据发生改变

三种写法比较

  1. 通过插值语句
  
    <div id="root">
        名: <input type="text" v-model:value="firstName"><br>
        姓: <input type="text" v-model:value="lastName"><br>
        全名: <span> {{firstName}}-{{lastName}}</span>
    </div>
    <script>
        new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三'
            }
        })
    </script>
  1. 通过methods
 <script>
        new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三'
            },
            methods:{
            fullName(){
            return this.firstName + '-' + this.lastName
            }
            }
        })
     </script>
  1. 通过计算属性
<script>
       const vm = new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三'
            },
            computed:{
                fullName:{
                    //只要fullName方法一被调用,就执行getter
                    //get什么时候调用? 1. 初次读取fullName时。2.所依赖的数据发生改变时。
                    get(){
                    // console.log(this) 此处的this代表vue
                    return this.firstName + '-' + this.lastName
                    }
                }
            }
           
        })
    </script>

小结

监视属性watch:

  1. 当被监视的属性变化时,回调函数自动调用,进行相关操作
  2. 监视的属性必须存在,才能进行监视
  3. 监视属性的两种写法:
    • new Vue 时传入watch配置
    • 通过vm.$watch监视
   <div id="root">
        <h2>今天 天气很{{info}}</h2>
        <button @click="changeMeather" >切换天气</button>
        <!-- 当处理的事情很简单的时候可以直接写 -->
        <!-- @xxx='yyy' yyy可以写一些简单的语句 -->
        <!-- <button @click="isHot = !isHot" >切换天气</button> -->
    </div>

    <script>
      const vm = new Vue({
            el:'#root',
            data:{
                isHot:true
            },
            //计算属性
            computed:{
             info:{
                get(){
                    return this.isHot ? '炎热' : '凉爽'
                }
             }
            },
            //方法
            methods:{
                changeMeather(){
                    return this.isHot = !this.isHot
                }
            },
            // 不光可以检测data中的属性还可以监测计算属性
            // 方法一================================
            //     watch:{
            //     //监测属性变化,  xxx:{}这种写法叫配置对象
            //     isHot:{
            //         immediate:true,//初始化时,让handler调用一下
            //         //handler什么时候调用?当ishot发生改变的时。
            //     handler(newValue,oldValue){
            //     console.log('isHost被修改了',newValue,oldValue)
            //     }
            //     }
            // }
        //================方法二通过vm实现====================
        })
        vm.$watch('isHot',{
            immediate:true,//初始化时,让handler调用一下
             handler(newValue,oldValue){
            console.log('isHost被修改了',newValue,oldValue)
        }
        })

    </script>

深度监视

深度监视:

  1. Vue中的watch默认不监测对象内部值的改变(一层)
  2. 配置deep:true可以监测对象内部值改变(多层)

备注:

  1. Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
  2. 使用watch时根据数据的具体结构,决定是否采用深度监视
  3. 箭头函数没有自己的this
<body>
    <div id="root">
        <h2>今天 天气很{{info}}</h2>
        <button @click="changeMeather" >切换天气</button>
    <hr>
    <h2>a的值是{{numbers.a}}</h2>
    <button @click="numbers.a++">点击让a的值加1</button>
    <h2>b的值是{{numbers.b}}</h2>
    <button @click="numbers.b++">点击让b的值加1</button>
    </div>

    <script>
      const vm = new Vue({
            el:'#root',
            data:{
                isHot:true,
                numbers:{
                    a:'1',
                    b:'1'
                }            },
            //计算属性
            computed:{
             info:{
                get(){
                    return this.isHot ? '炎热' : '凉爽'
                }
             }
            },
            //方法
            methods:{
                changeMeather(){
                    return this.isHot = !this.isHot
                }
            },
                watch:{
                //监测属性变化,  xxx:{}这种写法叫配置对象
                isHot:{
                    immediate:true,//初始化时,让handler调用一下
                    //handler什么时候调用?当ishot发生改变的时。
                handler(newValue,oldValue){
                console.log('isHost被修改了',newValue,oldValue)
                }
                },
                // 'numbers.a': {
                //     handler(){
                //         console.log("a被监视了")
                //     }
                    
                // }
                //需求检测numbers,只要里面的任何一个数据发生改变,
                numbers:{
                    //这样检测的是numbers这个配置对象的地址,即使里面的数据发生改变但地址不变,就监测不到,
                    //于是这里我们学习深度监测,让其向内继续监测
                    deep:true,  //这个配置项就实现了这个功能
                    //只要发生改变,就调用
                    handler(){
                    console.log('numbers被调用了')
                    }

                }
            }
        })

    </script>
</body>

简写

<script> 
methods:{
                changeMeather(){
                    return this.isHot = !this.isHot
                }
            },
                watch:{
                //正常写法
                // isHot:{
                //     immediate:true,//初始化时,让handler调用一下
                //     //handler什么时候调用?当ishot发生改变的时。
                // handler(newValue,oldValue){
                // console.log('isHost被修改了',newValue,oldValue)
                // }
                //当只用到handler的时候简写成方法
                // isHot(newValue,oldValue){
                // console.log('isHost被修改了',newValue,oldValue)
                // }
            }       
        })
        //使用vm对象简写
        vm.$watch('isHot',function(newValue,oldValue){
            console.log('isHost被修改了',newValue,oldValue)
        })
    </script>

用监视属性来改写计算属性

  <div id="root">
      姓: <input type="text" v-model="firstName"><br>
      名: <input type="text" v-model="lastName"><br>
      全名: <span>{{fullName}}</span>
    </div>

    <script>
       const vm = new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三',
                fullName:'张-三'
            },
           watch:{
            firstName(val){
             return this.fullName = val + '-' + this.lastName
            },
            lastName(val){
             return this.fullName = this.firstName + '-' + val
            }
           }
        })
    </script>

computed和watch之间的区别:

  1. computed能完成的功能,watch都可以完成
  2. watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作

两个重要 的原则:

  1. 所被 Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件对象
  2. 所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数等,promise的回调函数),最好写成箭头函数,这样this的指向才是vm或组件对象。

绑定样式

绑定class样式

   <div id="root">
        <!-- 绑定 class样式--字符串写法,适用于:样式的类名不确定,需要动态绑定 -->
        <div class="basic" :class="mood" @click="changeMood">{{name}}</div>
        <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定,冥冥中也不确定 -->
        <div class="basic" :class="classArr">{{name}}</div>
        <!--绑定class样式--对象写法,适用于:要绑定的样式个数确定,名字也确定,但要 动态决定用不用 -->
        <div class="basic" :class="classObj">{{name}}</div>
    </div>
    <script>
        new Vue({
            el:'#root',
            data:{
                name:'天气',
                mood:'',
                classArr:['a','b','c'],
                classObj:{
                    a:true,
                    b:true,
                }
            },
            methods: {
                changeMood(){
                    this.mood = ''
                }
            },  
        })
    </script>

绑定style样式

  • 对象里面的key不能瞎写
<div class="basic" :style="styleObj">{{name}}</div>

 data:{
                styleObj:{
                    fontSize:'40px'
                }
            },

条件渲染

  1. v-if

    写法:

    • v-if=‘表达式’
    • v-else-if=‘表达式’
    • v-else

    适用于:切换频率较低的场景

    特点:不展示的dom元素直接移除

    注意:v-if 可以和v-else-if,v-else 一块使用,但要求结构不能被破坏

  2. v-show

    写法:v-show=‘表达式’

    适用于:切换频率比较高的场景

    特点:不展示的dom元素未被移除

  3. 备注:使用v-if的时,元素可能无法获取到,而使用v-show的时候元素一定能获取到

<div id="root">
        <h1 >n 的值为{{n}}</h1>
         <!-- 需求1 让标签隐藏  v-show  -->
        <!-- <h1 v-show="false">n 的值为{{n}}</h1> -->
        <button @click="n++">点击让n加1</button>
        <!-- 使用v-if,v-else-if,v-else的时候要把标签放在一块形成一个组合来使用 -->
        <h2 v-if="n === 1">vue</h2>
        <h2 v-else-if="n === 2">java</h2>
        <h2 v-else>我权限最大</h2>
        

        <!-- 需求,当n===1的时候让三个标签都显示 -->
        <!--相比于div包裹, tempate的优点不影响页面结构,使用完之后 ,就被脱掉了
        不能和v-show 一块使用 -->
        <template v-if="n === 1">
           <h1>111</h1> 
           <h1>111</h1> 
           <h1>111</h1> 
        </template>

列表渲染

<body>
    <div id="root">
        <h2>人员列表</h2>
        <!-- 遍历数组 -->
        <ul>
            <li v-for="(p,index) in persions" :key="index">
                {{p.name}}-{{p.age}} ----{{index}}
            </li>
        </ul>
        <!-- 遍历对象 -->
        <ul>
            <li v-for="(p,index) in car" ::key="index">
                {{index}}----{{p}}
            </li>
        </ul>
        <!-- 遍历字符串 -->
        <h2>遍历字符串</h2>
        <ul>
            <li v-for="(char,index) in str" ::key="index">
                {{char}}--{{index}}
            </li>
        </ul>
        <h2>遍历指定次数</h2>
        <ul>
            <li v-for="(item,index) in 5" :key="index"> 
                {{item}}--{{index}}
            </li>
        </ul>

    </div>
    <script>
        new Vue({
            el:'#root',
            data:{
             persions:[
                {name:'张三',age:'18'},
                {name:'李四',age:'17'},
                {name:'王五',age:'19'}
             ],
             car:{
                name:'奥迪a8',
                price:'70w'
             },
             str:'hello'

            }
        })
    </script>

key的作用与原理

场景:在数据前面增加数据的时候,不用使用index作为key的唯一标识,

  1. 虚拟dom中key的作用:

    key是虚拟dom对象的标识,当状态中的数据发生变化时,vue会根据新数据生成新的虚拟 dom

    随后vue进行新虚拟dom与旧虚拟dom的差异比较

  2. 对比规则:

    • 旧虚拟dom中找到与新虚拟dom相同的key:
      • 若虚拟dom中内容没变,直接使用之前的真实dom
      • 若虚拟dom中内容变了,则生成新的真实dom,随后替换掉页面中之前的真实dom
    • 旧虚拟dom中未找到与新虚拟dom相同的key,创建新的真实dom,随后渲染到页面。
  3. 用index作为key可能会引发的问题

    • 若对数据进行:逆序添加,逆序删除等破坏顺序操作:

      会产生没有必要的真实dom更新===》界面效果没问题,但效率低

    • 如果结构中还包含输入类 的dom:

      会产生错误dom更新====》界面有问题

  4. 开发中如何选择key?

  • 最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号

  • 如果不存在对数据的逆序添加,逆序删除等破坏顺序操作,仅用于渲染列表用于展示,

    使用index作为key是没问题的。

列表过滤

<div id="root">
        <h2>人员列表</h2>
        <input type="text" placeholder="请输入姓名"  v-model="keyWords">
        <ul>
            <li v-for="(p,index) in filPersions">
                {{p.name}}-{{p.age}} -{{p.sex}}
            </li>
        </ul>
    </div>
    <script>
        // 使用监视属性watch实现
        //#region
        /* new Vue({
            el:'#root',
            data:{
             keyWords:'',
             persions:[
                {name:'马冬梅',age:19,sex:'女'},
                {name:'周冬雨',age:20,sex:'女'},
                {name:'周杰伦',age:21,sex:'男'},
                {name:'温兆伦',age:22,sex:'男'}
             ],
             filPersions:[]
            },
            watch:{
             keyWords:{
                immediate:true,
                handler(val){
                    this.filPersions = this.persions.filter((p)=>{
                        return p.name.indexOf(val) !== -1
                    })                      
                }
             }
            }
        }) */
        //#endregion
    
        //使用计算属性来实现
        new Vue({
            el:'#root',
            data:{
             keyWords:'',
             persions:[
                {name:'马冬梅',age:19,sex:'女'},
                {name:'周冬雨',age:20,sex:'女'},
                {name:'周杰伦',age:21,sex:'男'},
                {name:'温兆伦',age:22,sex:'男'}
             ]
            },
            computed:{
                /* filPersions(){
                  return this.persions.filter((p)=>{
                     return  p.name.indexOf(this.keyWords) !== -1
                    })
                } */
                filPersions:{
                    get(){
                        return this.persions.filter((p)=>{
                     return  p.name.indexOf(this.keyWords) !== -1
                    })
                    }
                }
            }
        })
      
    </script>

列表排序

<body>
    <div id="root">
        <h2>人员列表</h2>
        <input type="text" placeholder="请输入姓名"  v-model="keyWords">
        <button @click="sortType=2">升序排列</button>
        <button @click="sortType=1">降序排列</button>
        <button @click="sortType=0">原顺序</button>
        <ul>
            <li v-for="(p,index) in filPersions">
                {{p.name}}-{{p.age}} -{{p.sex}}
            </li>
        </ul>
    </div>
    <script>
        new Vue({
            el:'#root',
            data:{
             keyWords:'',
             sortType:0,
             persions:[
                {name:'马冬梅',age:19,sex:'女'},
                {name:'周冬雨',age:20,sex:'女'},
                {name:'周杰伦',age:21,sex:'男'},
                {name:'温兆伦',age:22,sex:'男'}
             ]
            },
            computed:{
                filPersions:{
                    get(){
                        const arr = this.persions.filter((p)=>{
                     return  p.name.indexOf(this.keyWords) !== -1
                    })
                    if(this.sortType){
                     arr.sort((p1,p2)=>{
                       return this.sortType == 1? p2.age - p1.age : p1.age - p2.age 
                     })
                    }
                    return arr
                    }
                }
            }
        })
      
    </script>

vue自身数据监测的原理

 <div id="root">
        <h2>人员列表</h2>
        <button @click="updateMei">点击更新马冬梅的信息</button>
        <ul>
            <li v-for="(p,index) in persions">
                {{p.name}}-{{p.age}} -{{p.sex}}
            </li>
        </ul>
    </div>
    <script>
       const vm = new Vue({
            el:'#root',
            data:{
             keyWords:'',
             persions:[
                {name:'马冬梅',age:19,sex:'女'},
                {name:'周冬雨',age:20,sex:'女'},
                {name:'周杰伦',age:21,sex:'男'},
                {name:'温兆伦',age:22,sex:'男'}
             ]
            },
            methods:{
                updateMei(){
                    // this.persions[0].name = '马老师'//x有效
                    // this.persions[0].age = '50'//x有效
                    // this.persions[0].sex = '男'//x有效
                    this.persions[0] = {name:'马老师',age:60,sex:'男'}
                }
            }
        })
      
    </script>

小案例

 <script>
    //   这只是一个简单的写法案例,vue比这个复杂的多,它不仅可以解析第一层的属性,还可以解析属性包裹着的属性
    //通过递归实现
    //该案例是没有办法解析里面的属性的
        let data = {
          name:'叶落',
          address:'山东'
        }

       
        const obs = new Observer(data)

        //准备一个vm对象
        let vm = {}
        vm._data = data = obs

       //先写一个构造方法,监测对象属性的变化,所有我们需要给它传递一个形参对象
       function Observer(obj){
        //首先把监测对象中的属性形成一个数组
        const keys = Object.keys(obj)
        //通过Object.defineProperty数据代理
        keys.forEach((k)=>{
        Object.defineProperty(this,k,{
            get(){
                return obj[k]
            },
            set(val){
                console.log('${k}被修改了,我要去解析模板,生成新的虚拟dom......我要开始忙了')
                return obj[k] = val
            }
        })
        })  
       }

    </script>

总结Vue数据监测

  1. vue会监视data中所有层次的数据

  2. 如何监测对象中的数据?

    通过setter实现监视,且要哎new Vue 时就传入要监测的数据

    • 对象中后追加的属性,Vue默认不做响应式处理
    • 如需给后 添加的属性做响应式,请使用如下api:
      • Vue.set(target, propertyName/index, value)
      • vm.$set(target,propertName/index,value)
  3. 如何监测数组中的数据?

    通过包裹数组更新元素的方法实现,本质就是做了两件事:

    • 调用原生对应的方法对数据进行更新
    • 重新解析模板,进而更新页面
  4. 在Vue修改数组中的某个元素一定要用如下方法():

    • 使用这些api:push() , pop() , shift() unshift() splice() sort() reverse()
    • Vue.set() 或vm.$set()

特别注意:Vue.set() 和vm.$set() 不能给vm或vm的根数据对象添加属性!!!

    <div id="root">
        <h1>学生信息</h1>
        <button @click="student.age++">年龄+1岁</button>
        <button @click="addSex">添加性别属性,默认值:男</button>
        <button @click="student.sex= '未知'">修改性别</button>
        <button @click="addFriend">在列表首位添加一个朋友</button>
        <button @click="updateFirstFriend">修改第一个朋友的名字为:张三</button>  
        <button @click="student.hobby.push('学习')">添加一个爱好</button>
        <button @click="updateFirstHobby">修改第一个爱好为:开车</button>       
        <h3>姓名:{{student.name}}</h3>
        <h3>年龄:{{student.age}}</h3>
        <h3>爱好:</h3>
        <h3 v-if="student.sex">性别:{{student.sex}}</h3>
        <ul>
            <li v-for="(h,index) in student.hobby" :key="index">
                {{h}}
            </li>
        </ul>
        <h3>朋友们:</h3>
        <ul>
            <li v-for="(f,index) in student.friends" :key="index">
                {{f.name}} ---{{f.age}}
            </li>
        </ul>
    </div>
    <script>
      const vm = new Vue({
            el:'#root',
            data:{
                student:{
                    name:'tom',
                    age:18,
                    hobby:['抽烟','喝酒','烫头'],
                    friends:[
                      {name:'jerry',age:18},
                      {name:'xiao',age:89}
                    ]
                }
            },
            methods:{
            addSex(){
                // Vue.set(this.student,'sex','男')
                this.$set(this.student,'sex','男')
            },
            addFriend(){
                //操作数组,用到了被vue封装的方法,所有会解析模板,实现响应式
                this.student.friends.unshift({name:'liu',age:11})
            },
            updateFirstFriend(){
                this.student.friends[0].name = '张三'
            },
            updateFirstHobby(){
                // this.student.hobby.splice(0,1,'开车')
                Vue.set(this.student.hobby,0,'学习')
            }
        }
        })
    </script>

收集表单数据

<div id="root">
            <!-- ctrl+F 高亮, -->
        <form @submit.prevent="demo">
            账号:<input type="text" v-model.trim="userInfo.account"><br><br>
            密码:<input type="password" v-model="userInfo.password"><br><br>
            性别:男<input type="radio" name="sex" value="male" v-model="userInfo.sex"><input type="radio" name="sex" value="female" v-model="userInfo.sex"><br><br>
            年龄:<input type="number" v-model.number="userInfo.age"><br><br>
            爱好:抽烟<input type="checkbox" v-model="userInfo.hobby" value="抽烟">
            喝酒<input type="checkbox" v-model="userInfo.hobby" value="喝酒">
            烫头<input type="checkbox" v-model="userInfo.hobby" value="烫头"><br><br>
            所属校区:<select name="" id="" v-model="userInfo.city">
                <option value="">请选择校区</option>
                <option value="shanghai">上海</option>
                <option value="beijing">北京</option>
                <option value="chenzhen">深圳</option>
                <option value="guangzhou">广州</option>
            </select><br><br>
            其他信息:<textarea v-model.lazy="userInfo.other"></textarea><br><br>
            <input type="checkbox" v-model="userInfo.agree">阅读并同意 <a href="#">《用户协议》</a><br><br>
            <button>提交</button>
        </form>
     </div>
         <script>
        new Vue({
            el:'#root',
            data:{
                userInfo:{
                    account:'',
                    password:'',
                    sex:'',
                    age:'',
                    hobby:[],
                    city:'',
                    other:'',
                    agree:''
                }
            },
            methods:{
                demo(){
                    console.log(JSON.stringify(this.userInfo))
                }
            }

        })
         </script>

总结

收集表单数据:

若:

若: 则v-model 受经济的是value值,且要给标签配置value

若:

  1. 没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选, 是布尔值)
  2. 配置input的value属性:
    • v-model的初始值是非数组,那么收集的就是checked
    • v-model的初始值是数组,那么收集的就是value组成的数组

备注: v-model 的三个修饰符:

  • lazy:失去焦点再收集数据
  • number:输入字符串转为有效的数字
  • trim:输入首尾空格过滤

过滤器

<div id="root">
      <h2>显示格式化后的标签</h2>
      <!-- 计算属性实现 -->
      <h3>现在的时间是:{{fmtTime}}</h3>
      <!-- methods实现 -->
      <h3>现在的时间是:{{getFmtTime()}}</h3>
      <!-- 过滤器实现 -->
      <h3>现在的时间是:{{time | timeFormater}}</h3>
      <!-- 需求只要年月日 -->
      <!-- 过滤器,第一个参数永远是time , 不管过滤函数有没有括号 -->
      <h4>现在的时间是:{{time | timeFormater('YYYY_MM_DD')}}</h4>
      <!-- 在过滤的基础上继续过滤 -->
      <h4>现在的时间是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h4>


    </div>
    <script>
        // 全局过滤器,过滤器可以用于v-bind与插值语法
        Vue.filter('mySlice',function(value){
            return value.slice(0,4)
            })
        new Vue({
            el:'#root',
            data:{
                time:1621561377603
            },
            computed:{
                fmtTime(){
                    return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
                }
            },
            methods:{
                getFmtTime(){
                    return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
                }
            },
            filters:{
                //优秀的一点,,形参默认值!!!  这个为局部过滤器
                timeFormater:function(value,str='YYYY-MM-DD HH:mm:ss'){
                    return dayjs(value).format(str)
                }
            }
        })
    </script>

总结:

过滤器:

​ 定义:对要显示的数据进行特定格式化后再显示(适合一些简单的逻辑处理)

​ 语法:

  1. 注册过滤器:Vue。filter(name,callback) 或 new Vue{(filters:{})}
  2. 使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = ‘xxx | 过滤器名’

备注:

  1. 过滤器也 可以接收额外参数,多个过滤器也可以串联

  2. 并没有改变原来的数据,是产生新的对应的数据

    现在的时间是:{{time | timeFormater('YYYY_MM_DD')}}
    现在的时间是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}

### 总结:

过滤器:

​    定义:对要显示的数据进行特定格式化后再显示(适合一些简单的逻辑处理)

​    语法:

1. 注册过滤器:Vue。filter(name,callback) 或 new  Vue{(filters:{})}
2. 使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = 'xxx | 过滤器名'

备注:

1. 过滤器也 可以接收额外参数,多个过滤器也可以串联
2. 并没有改变原来的数据,是产生新的对应的数据



;