Vue语法和常用特性

2020-08-22  本文已影响0人  Scincyc

1.Vue基础语法

Vue 是什么?

1.1 插值表达式语法:{{}}

<!-- 1.提供标签填充数据 -->
<div id="app">
    <div>{{msg}}</div>
</div>
<!-- 2.引入vue.js库文件 -->
<script type="text/javascript" src="js/vue.js"></script>
<script>
    // 3.vue语法功能
    var vm = new Vue({
        // 挂载的元素
        el: "#app",
        // data存放渲染到页面的数据,是一个对象
        data: {
            msg: "Hello vue"
        }
    })
</script>

插值表达式存在闪烁的问题,原理就是页面先显示插值表达式,再迅速的替换成对应的数据

1.2 指令

v-cloak

v-text

<div id="app">
    <p v-text="msg"></p>
    <p>
        <!-- Vue中只有在标签的内容中 才用插值语法 -->
        {{msg}}
    </p>
</div>

<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'Hello Vue.js'
        }
    });

</script>

v-html

v-pre

    <span v-pre>{{ this will not be compiled }}</span>    
    <!--  显示的是{{ this will not be compiled }}  -->
    <span v-pre>{{msg}}</span>  
     <!--   即使data里面定义了msg这里仍然是显示的{{msg}}  -->
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'Hello Vue.js'
        }
    });

</script>

v-once

  <!-- 即使data里面定义了msg 后期我们修改了 仍然显示的是第一次data里面存储的数据即 Hello Vue.js  -->
     <span v-once>{{ msg}}</span>    
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'Hello Vue.js'
        }
    });
</script>

双向数据绑定

v-model

 <div id="app">
      <div>{{msg}}</div>
      <div>
          当输入框中内容改变的时候,  页面上的msg  会自动更新
        <input type="text" v-model='msg'>
      </div>
  </div>

1.3 mvvm

1.4 v-on事件绑定

<div id="app">
    <!-- 事件绑定等价写法 -->
    <div v-on:click='handle'>{{msg}}</div>
<div @click='handle'>{{msg}}</div>
<div @click='handle()'>{{msg}}</div>
</div>

<script type="text/javascript" src="js/vue.js"></script>
<script>
    // 3.vue语法功能
    var vm = new Vue({
        // 获取元素
        el: "#app",
        // data存放渲染到页面的数据
        data: {
            msg: "Hello vue"
        },
        methods: {
            handle: function () {
                // 这里的this指向vue的实例对象
                console.log(this === vm);
                // 在函数中使用data中的数据 必须加this
                console.log(this.msg);
            }
        }
    })
</script>

v-on传入参数

<div id="app">
    <div>{{num}}</div>
    <div>
        <!--1. 如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的第一个参数 -->
        <button v-on:click='handle1'>点击1</button>
        <!-- 2、如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,并且事件对象的名称必须是$event 
-->
        <button v-on:click='handle2(123, 456, $event)'>点击2</button>
    </div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: '#app',
        data: {
            num: 0
        },
        methods: {
            handle1: function(event) {
                console.log(event.target.innerHTML)
            },
            handle2: function(p, p1, event) {
                console.log(p, p1)
                console.log(event.target.innerHTML)
                this.num++;
            }
        }
    });
</script>

事件修饰符

<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联   即阻止冒泡也阻止默认事件 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

按键修饰符

<!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` -->
<input v-on:keyup.13="submit">

<!-- -当点击enter 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">

<!--当点击enter或者space时  时调用 `vm.alertMe()`   -->
<input type="text" v-on:keyup.enter.space="alertMe" >

常用的按键修饰符
.enter =>    enter键
.tab => tab键
.delete (捕获“删除”和“退格”按键) =>  删除键
.esc => 取消键
.space =>  空格键
.up =>  上
.down =>  下
.left =>  左
.right =>  右

<script>
    var vm = new Vue({
        el:"#app",
        methods: {
              submit:function(){},
              alertMe:function(){},
        }
    })
</script>

自定义按键修饰符别名

<div id="app">
    预先定义了keycode 116(即F5)的别名为f5,因此在文字输入框中按下F5,会触发prompt方法
    <input type="text" v-on:keydown.f5="prompt()">
</div>

<script>
    
    Vue.config.keyCodes.f5 = 116;

    let app = new Vue({
        el: '#app',
        methods: {
            prompt: function() {
                alert('我是 F5!');
            }
        }
    });
</script>

1.5 v-bind属性绑定

<!-- 绑定一个属性 -->
<img v-bind:src="imageSrc">

<!-- 缩写 -->
<img :src="imageSrc">

绑定对象

1、 v-bind 中支持绑定一个对象 
    如果绑定的是一个对象 则 键为 对应的类名  值 为对应data中的数据 
<!-- 
    HTML最终渲染为 <ul class="box textColor textSize"></ul>
    注意:
        textColor,textSize对应的渲染到页面上的CSS类名   
        isColor,isSize对应vue data中的数据  如果为true,则对应的类名渲染到页面上 
        当 isColor 和 isSize 变化时,class列表将相应的更新,
        例如,将isSize改成false,class列表将变为 <ul class="box textColor"></ul>
-->

<ul class="box" v-bind:class="{textColor:isColor, textSize:isSize}">
    <li>学习Vue</li>
    <li>学习Node</li>
    <li>学习React</li>
</ul>
  <div v-bind:style="{color:activeColor,fontSize:activeSize}">对象语法</div>

<sript>
var vm= new Vue({
    el:'.box',
    data:{
        isColor:true,
        isSize:true,
        activeColor:"red",
        activeSize:"25px",
    }
})
</sript>
<style>

    .box{
        border:1px dashed #f0f;
    }
    .textColor{
        color:#f00;
        background-color:#eef;
    }
    .textSize{
        font-size:30px;
        font-weight:bold;
    }
</style>

绑定class

2、  v-bind 中支持绑定一个数组    数组中classA和 classB 对应为data中的数据

这里的classA  对用data 中的  classA
这里的classB  对用data 中的  classB
<ul class="box" :class="[classA, classB]">
    <li>学习Vue</li>
    <li>学习Node</li>
    <li>学习React</li>
</ul>
<script>
var vm= new Vue({
    el:'.box',
    data:{
        classA:'textColor',
        classB:'textSize'
    }
})
</script>
<style>
    .box{
        border:1px dashed #f0f;
    }
    .textColor{
        color:#f00;
        background-color:#eef;
    }
    .textSize{
        font-size:30px;
        font-weight:bold;
    }
</style>

绑定对象和绑定数组 的区别

绑定style

 <div v-bind:style="styleObject">绑定样式对象</div>'
 
<!-- CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来)    -->
 <div v-bind:style="{ color: activeColor, fontSize: fontSize,background:'red' }">内联样式</div>

<!--组语法可以将多个样式对象应用到同一个元素 -->
<div v-bind:style="[styleObj1, styleObj2]"></div>


<script>
    new Vue({
      el: '#app',
      data: {
        styleObject: {
          color: 'green',
          fontSize: '30px',
          background:'red'
        },
        activeColor: 'green',
        fontSize: "30px"
      },
      styleObj1: {
             color: 'red'
       },
       styleObj2: {
            fontSize: '30px'
       }

</script>

1.6 分支结构

v-if 使用场景

<div id="app">
    <!--  判断是否加载,如果为真,就加载,否则不加载-->
    <span v-if="flag">
        如果flag为true则显示,false不显示!
    </span>
</div>

<script>
    var vm = new Vue({
        el:"#app",
        data:{
            flag:true
        }
    })
</script>

----------------------------------------------------------

<div v-if="type === 'A'">
    A
</div>
<!-- v-else-if紧跟在v-if或v-else-if之后   表示v-if条件不成立时执行-->
<div v-else-if="type === 'B'">
    B
</div>
<div v-else-if="type === 'C'">
    C
</div>
<!-- v-else紧跟在v-if或v-else-if之后-->
<div v-else>
    Not A/B/C
</div>

<script>
    new Vue({
        el: '#app',
        data: {
            type: 'C'
        }
    })
</script>

v-show 和 v-if的区别

1.7 循环结构

v-for

<ul id="example-1">
   <!-- 循环结构-遍历数组  
    item 是我们自己定义的一个名字  代表数组里面的每一项  
    items对应的是 data中的数组-->
  <li v-for="item in items">
    {{ item.message }}
  </li> 

</ul>
<script>
 new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ],
   
  }
})
</script>
<!--  循环结构-遍历对象
v 代表   对象的value
k  代表对象的 键 
i  代表索引 
---> 
<div v-if='v==13' v-for='(v,k,i) in obj'>{{v + '---' + k + '---' + i}}</div>

<script>
 new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ],
    obj: {
        uname: 'zhangsan',
        age: 13,
        gender: 'female'
    }
  }
})
</script>
<ul>
  <li v-for="item in items" :key="item.id">...</li>
</ul>

1.8 案例选项卡

1)HTML 结构

`
    <div id="app">
        <div class="tab">
            <!--  tab栏  -->
            <ul>
                <li class="active">apple</li>
                <li class="">orange</li>
                <li class="">lemon</li>
            </ul>
              <!--  对应显示的图片 -->
            <div class="current"><img src="img/apple.png"></div>
            <div class=""><img src="img/orange.png"></div>
            <div class=""><img src="img/lemon.png"></div>
        </div>
    </div>


`

2)提供的数据

         list: [{
                    id: 1,
                    title: 'apple',
                    path: 'img/apple.png'
                }, {
                    id: 2,
                    title: 'orange',
                    path: 'img/orange.png'
                }, {
                    id: 3,
                    title: 'lemon',
                    path: 'img/lemon.png'
                }]

3)把数据渲染到页面

4)给每一个tab栏添加事件,并让选中的高亮

2. Vue常用特性

2.1 表单基本操作

1、获取单选框中的值

<!-- 
1、 两个单选框需要同时通过v-model 双向绑定 一个值 
2、 每一个单选框必须要有value属性  且value 值不能一样 
3、 当某一个单选框选中的时候 v-model  会将当前的 value值 改变 data 中的 数据

gender 的值就是选中的值,我们只需要实时监控他的值就可以了
-->
<input type="radio" id="male" value="1" v-model='gender'>
<label for="male">男</label>

<input type="radio" id="female" value="2" v-model='gender'>
<label for="female">女</label>

<script>
    new Vue({
         data: {
             // 默认会让当前的 value 值为 2 的单选框选中
                gender: 2,  
            },
    })

</script>

2、获取复选框中的值

    <!-- 
        1、 复选框需要同时通过v-model 双向绑定 一个值 
        2、 每一个复选框必须要有value属性  且value 值不能一样 
        3、 当某一个单选框选中的时候 v-model  会将当前的选中的value值 改变成 data 中的 数据

        hobby 的值就是选中的值,我们只需要实时监控他的值就可以了
    -->

<div>
   <span>爱好:</span>
   <input type="checkbox" id="ball" value="1" v-model='hobby'>
   <label for="ball">篮球</label>
   <input type="checkbox" id="sing" value="2" v-model='hobby'>
   <label for="sing">唱歌</label>
   <input type="checkbox" id="code" value="3" v-model='hobby'>
   <label for="code">写代码</label>
 </div>
<script>
    new Vue({
         data: {
                // 默认会让当前的 value 值为 2 和 3 的复选框选中
                hobby: ['2', '3'],
            },
    })
</script>

3、获取下拉框和文本框中的值

<div>
    <span>职业:</span>
    <!--
1、 需要给select  通过v-model 双向绑定 一个值 
2、 每一个option  必须要有value属性  且value 值不能一样 
3、 当某一个option选中的时候 v-model  会将当前的 value值 改变 data 中的 数据
occupation 的值就是选中的值,我们只需要实时监控他的值就可以了
-->
    <!-- multiple  多选 -->
    <select v-model='occupation' multiple>
        <option value="0">请选择职业...</option>
        <option value="1">教师</option>
        <option value="2">软件工程师</option>
        <option value="3">律师</option>
    </select>
    <!-- textarea 是 一个双标签   不需要绑定value 属性的  -->
    <textarea v-model='desc'></textarea>
</div>
<script>
    new Vue({
        data: {
            // 默认会让当前的 value 值为 2 和 3 的下拉框选中
            occupation: ['2', '3'],
            desc: 'nihao'
        },
    })
</script>

2.2 表单修饰符

2.3 自定义指令

Vue.directive 注册全局指令

<!-- 
  使用自定义的指令,只需在对用的元素中,加上'v-'的前缀形成类似于内部指令'v-if','v-text'的形式。 
-->
<input type="text" v-focus>
<script>
// 注意点: 
//   1、 在自定义指令中  如果以驼峰命名的方式定义 如  Vue.directive('focusA',function(){}) 
//   2、 在HTML中使用的时候 只能通过 v-focus-a 来使用 

// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
    //钩子函数, 当绑定元素插入到 DOM 时调用。 其中 el为dom元素
    inserted: function (el) {
            // 聚焦元素
            el.focus();
    }
});
new Vue({
  el:'#app'
});
</script>

全局指令 带参数

<input type="text" v-color='msg'>
<script type="text/javascript">
    /*
      自定义指令-带参数
      bind - 只调用一次,在指令第一次绑定到元素上时候调用
    */
    Vue.directive('color', {
        // bind声明周期, 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
        // el 为当前自定义指令的DOM元素  
        // binding 为自定义的函数形参   通过自定义属性传递过来的值 存在 binding.value 里面
        bind: function(el, binding){
            // 根据指令的参数设置背景色
            // console.log(binding.value.color)//blue
            el.style.backgroundColor = binding.value.color;
        }
    });
    var vm = new Vue({
        el: '#app',
        data: {
            msg: {
                color: 'blue'
            }
        }
    });
</script>

自定义局部指令

<input type="text" v-color='msg'>
 <input type="text" v-focus>
 <script type="text/javascript">
    /*
      自定义指令-局部指令
    */
    var vm = new Vue({
      el: '#app',
      data: {
        msg: {
          color: 'red'
        }
      },
      //局部指令,需要定义在  directives 的选项
      directives: {
        color: {
          bind: function(el, binding){
            el.style.backgroundColor = binding.value.color;
          }
        },
        focus: {
          inserted: function(el) {
            el.focus();
          }
        }
      }
    });
  </script>

2.4 计算属性 computed

 <div id="app">
     <!--  
        当多次调用 reverseString  的时候 
        只要里面的 num 值不改变 他会把第一次计算的结果直接返回
        直到data 中的num值改变 计算属性才会重新发生计算
     -->
    <div>{{reverseString}}</div>
    <div>{{reverseString}}</div>
     <!-- 调用methods中的方法的时候  他每次会重新调用 -->
    <div>{{reverseMessage()}}</div>
    <div>{{reverseMessage()}}</div>
  </div>
  <script type="text/javascript">
    /*
      计算属性与方法的区别:计算属性是基于依赖进行缓存的,而方法不缓存
    */
    var vm = new Vue({
      el: '#app',
      data: {
        msg: 'Nihao',
        num: 100
      },
      methods: {
        reverseMessage: function(){
          console.log('methods')
          return this.msg.split('').reverse().join('');
        }
      },
      //computed 属性定义和data、methods平级 
      computed: {
        //  reverseString   这个是我们自己定义的名字 
        reverseString: function(){
          console.log('computed')
          var total = 0;
          //  当data中的num值改变时  reverseString会自动发生计算  
          for(var i=0;i<=this.num;i++){
            total += i;
          }
          // 这里一定要有return 否则调用reverseString时无法拿到结果    
          return total;
        }
      }
    });
  </script>

2.5侦听器 watch

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

<script type="text/javascript">
    /*
              侦听器
            */
    var vm = new Vue({
        el: '#app',
        data: {
            firstName: 'Jim',
            lastName: 'Green',
            // fullName: 'Jim Green'
        },
        //watch  属性定义和data、methods平级 
        watch: {
            //   注意:  这里firstName  对应着data中的firstName 
            //   当 firstName值改变的时候  会自动触发watch
            firstName: function(val) {
                this.fullName = val + ' ' + this.lastName;
            },
            //   注意:  这里lastName 对应着data中的lastName 
            lastName: function(val) {
                this.fullName = this.firstName + ' ' + val;
            }
        }
    });
</script>

2.6 过滤器

<div id="app">
    <input type="text" v-model='msg'>
    <!-- upper 被定义为接收单个参数的过滤器函数,表达式  msg  的值将作为参数传入到函数中 -->
    <div>{{msg | upper}}</div>
    <!--  
支持级联操作
upper  被定义为接收单个参数的过滤器函数,表达式msg 的值将作为参数传入到函数中。
然后继续调用同样被定义为接收单个参数的过滤器 lower ,将upper 的结果传递到lower中
-->
    <div>{{msg | upper | lower}}</div>
    <div :abc='msg | upper'>测试数据</div>
</div>

<script type="text/javascript">
    //  lower  为全局过滤器     
    Vue.filter('lower', function(val) {
        return val.charAt(0).toLowerCase() + val.slice(1);
    });
    var vm = new Vue({
        el: '#app',
        data: {
            msg: ''
        },
        //filters  属性 定义 和 data 已经 methods 平级 
        //  定义filters 中的过滤器为局部过滤器 
        filters: {
            //   upper  自定义的过滤器名字 
            //    upper 被定义为接收单个参数的过滤器函数,表达式  msg  的值将作为参数传入到函数中
            upper: function(val) {
                //  过滤器中一定要有返回值 这样外界使用过滤器的时候才能拿到结果
                return val.charAt(0).toUpperCase() + val.slice(1);
            }
        }
    });
</script>

过滤器中传递参数

    <div id="box">
        <!--
            filterA 被定义为接收三个参数的过滤器函数。
            其中 message 的值作为第一个参数,
            普通字符串 'arg1' 作为第二个参数,表达式 arg2 的值作为第三个参数。
        -->
        {{ message | filterA('arg1', 'arg2') }}
    </div>
    <script>
        // 在过滤器中 第一个参数 对应的是  管道符前面的数据   n  此时对应 message
        // 第2个参数  a 对应 实参  arg1 字符串
        // 第3个参数  b 对应 实参  arg2 字符串
        Vue.filter('filterA',function(n,a,b){
            if(n<10){
                return n+a;
            }else{
                return n+b;
            }
        });
        
        new Vue({
            el:"#box",
            data:{
                message: "哈哈哈"
            }
        })

    </script>

2.7 生命周期

常用的 钩子函数

beforeCreate 在实例初始化之后,数据观测和事件配置之前被调用 此时data 和 methods 以及页面的DOM结构都没有初始化 什么都做不了
created 在实例创建完成后被立即调用此时data 和 methods已经可以使用 但是页面还没有渲染出来
beforeMount 在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已
mounted⭐初始化完成 el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。 数据已经真实渲染到页面上 在这个钩子函数里面我们可以使用一些第三方的插件
beforeUpdate 数据更新时调用,发生在虚拟DOM打补丁之前。 页面上数据还是旧的
updated 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。 页面上数据已经替换成最新的
beforeDestroy 实例销毁之前调用
destroyed 实例销毁后调用

2.8 数组变异方法(修改原有数组)

push() 往数组最后面添加一个元素,成功返回当前数组的长度
pop() 删除数组的最后一个元素,成功返回删除元素的值
shift() 删除数组的第一个元素,成功返回删除元素的值
unshift() 往数组最前面添加一个元素,成功返回当前数组的长度
splice() 有三个参数,第一个是想要删除的元素的下标(必选),第二个是想要删除的个数(必选),第三个是删除 后想要在原位置替换的值
sort() sort() 使数组按照字符编码默认从小到大排序,成功返回排序后的数组
reverse() reverse() 将数组倒序,成功返回倒序后的数组

2.9 替换数组(生成数组)

filter filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
concat concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组
slice slice() 方法可从已有的数组中返回选定的元素。该方法并不会修改数组,而是返回一个子数组

2.10 动态数组响应式数据

2.11 图书列表案例

1、 提供的静态数据

 var vm = new Vue({
      el: '#app',
      data: {
        books: [{
          id: 1,
          name: '三国演义',
          date: ''
        },{
          id: 2,
          name: '水浒传',
          date: ''
        },{
          id: 3,
          name: '红楼梦',
          date: ''
        },{
          id: 4,
          name: '西游记',
          date: ''
        }]
      }
    }); var vm = new Vue({
      el: '#app',
      data: {
        books: [{
          id: 1,
          name: '三国演义',
          date: ''
        },{
          id: 2,
          name: '水浒传',
          date: ''
        },{
          id: 3,
          name: '红楼梦',
          date: ''
        },{
          id: 4,
          name: '西游记',
          date: ''
        }]
      }
    });

2、 把提供好的数据渲染到页面上

 <tbody>
    <tr :key='item.id' v-for='item in books'>
       <!-- 对应的id 渲染到页面上 -->
       <td>{{item.id}}</td>
        <!-- 对应的name 渲染到页面上 -->
       <td>{{item.name}}</td>
       <td>{{item.date}}</td>
       <td>
         <!-- 阻止 a 标签的默认跳转 -->
         <a href="" @click.prevent>修改</a>
         <span>|</span>
          <a href="" @click.prevent>删除</a>
       </td>
     </tr>
</tbody>

3、 添加图书

<div>
  <h1>图书管理</h1>
  <div class="book">
       <div>
         <label for="id">
           编号:
         </label>
          <!-- 3.1、通过双向绑定获取到输入框中的输入的 id  -->
         <input type="text" id="id" v-model='id'>
         <label for="name">
           名称:
         </label>
           <!-- 3.2、通过双向绑定获取到输入框中的输入的 name  -->
         <input type="text" id="name" v-model='name'>
            <!-- 3.3、给按钮添加点击事件  -->
         <button @click='handle'>提交</button>
       </div>
  </div>
</div>
  <script type="text/javascript">
    /*
      图书管理-添加图书
    */
    var vm = new Vue({
      el: '#app',
      data: {
        id: '',
        name: '',
        books: [{
          id: 1,
          name: '三国演义',
          date: ''
        },{
          id: 2,
          name: '水浒传',
          date: ''
        },{
          id: 3,
          name: '红楼梦',
          date: ''
        },{
          id: 4,
          name: '西游记',
          date: ''
        }]
      },
      methods: {
        handle: function(){
          // 3.4 定义一个新的对象book 存储 获取到输入框中 书 的id和名字 
          var book = {};
          book.id = this.id;
          book.name = this.name;
          book.date = '';
         // 3.5 把book  通过数组的变异方法 push 放到    books 里面
          this.books.push(book);
          //3.6 清空输入框
          this.id = '';
          this.name = '';
        }
      }
    });
  </script>

4 修改图书-上

 <div id="app">
    <div class="grid">
      <div>
        <h1>图书管理</h1>
        <div class="book">
          <div>
            <label for="id">
              编号:
            </label>
            <input type="text" id="id" v-model='id' :disabled="flag">
            <label for="name">
              名称:
            </label>
            <input type="text" id="name" v-model='name'>
            <button @click='handle'>提交</button>
          </div>
        </div>
      </div>
      <table>
        <thead>
          <tr>
            <th>编号</th>
            <th>名称</th>
            <th>时间</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr :key='item.id' v-for='item in books'>
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <td>{{item.date}}</td>
            <td>
              <!--- 
                4.1  给修改按钮添加点击事件,  需要把当前的图书的id 传递过去 
                这样才知道需要修改的是哪一本书籍
                --->  
              <a href="" @click.prevent='toEdit(item.id)'>修改</a>
              <span>|</span>
              <a href="" @click.prevent>删除</a>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
 <script type="text/javascript">
    /*
      图书管理-添加图书
    */
    var vm = new Vue({
      el: '#app',
      data: {
        flag: false,
        id: '',
        name: '',
        books: [{
          id: 1,
          name: '三国演义',
          date: ''
        },{
          id: 2,
          name: '水浒传',
          date: ''
        },{
          id: 3,
          name: '红楼梦',
          date: ''
        },{
          id: 4,
          name: '西游记',
          date: ''
        }]
      },
      methods: {
        handle: function(){
          // 3.4 定义一个新的对象book 存储 获取到输入框中 书 的id和名字 
          var book = {};
          book.id = this.id;
          book.name = this.name;
          book.date = '';
         // 3.5 把book  通过数组的变异方法 push 放到    books 里面
          this.books.push(book);
          //3.6 清空输入框
          this.id = '';
          this.name = '';
        },
        toEdit: function(id){
          console.log(id)
          //4.2  根据传递过来的id 查出books 中 对应书籍的详细信息
          var book = this.books.filter(function(item){
            return item.id == id;
          });
          console.log(book)
          //4.3 把获取到的信息填充到表单
          // this.id   和  this.name 通过双向绑定 绑定到了表单中  一旦数据改变视图自动更新
          this.id = book[0].id;
          this.name = book[0].name;
        }
      }
    });
  </script>

5 修改图书-下

<div id="app">
    <div class="grid">
      <div>
        <h1>图书管理</h1>
        <div class="book">
          <div>
            <label for="id">
              编号:
            </label>
              <!-- 5.2 通过属性绑定 绑定 disabled 的属性  flag 为 true 即为禁用      -->
            <input type="text" id="id" v-model='id' :disabled="flag">
            <label for="name">
              名称:
            </label>
            <input type="text" id="name" v-model='name'>
            <button @click='handle'>提交</button>
          </div>
        </div>
      </div>
      <table>
        <thead>
          <tr>
            <th>编号</th>
            <th>名称</th>
            <th>时间</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr :key='item.id' v-for='item in books'>
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <td>{{item.date}}</td>
            <td>
              <a href="" @click.prevent='toEdit(item.id)'>修改</a>
              <span>|</span>
              <a href="" @click.prevent>删除</a>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>   
<script type="text/javascript">
        /*图书管理-添加图书*/
        var vm = new Vue({
            el: '#app',
            data: {
                // 5.1  定义一个标识符, 主要是控制 编辑状态下当前编辑书籍的id 不能被修改 
                // 即 处于编辑状态下 当前控制书籍编号的输入框禁用 
                flag: false,
                id: '',
                name: '',
              
            },
            methods: {
                handle: function() {
                   /*
                     5.4  复用添加方法   用户点击提交的时候依然执行 handle 中的逻辑
                         如果 flag为true 即 表单处于不可输入状态 此时执行的用户编辑数据数据    
                   */ 
                    if (this.flag) {
                        // 编辑图书
                        // 5.5  根据当前的ID去更新数组中对应的数据  
                        this.books.some((item) => {
                            if (item.id == this.id) {
                                // 箭头函数中 this 指向父级作用域的this 
                                item.name = this.name;
                                // 完成更新操作之后,需要终止循环
                                return true;
                            }
                        });
                        // 5.6 编辑完数据后表单要处以可以输入的状态
                        this.flag = false;
                    //  5.7  如果 flag为false  表单处于输入状态 此时执行的用户添加数据    
                    } else { 
                        var book = {};
                        book.id = this.id;
                        book.name = this.name;
                        book.date = '';
                        this.books.push(book);
                        // 清空表单
                        this.id = '';
                        this.name = '';
                    }
                    // 清空表单
                    this.id = '';
                    this.name = '';
                },
                toEdit: function(id) {
                     /*
                     5.3  flag 默认值为false   处于编辑状态 要把 flag 改为true 即当前表单为禁                      用 
                     */ 
                    this.flag = true;
                    console.log(id)
                    var book = this.books.filter(function(item) {
                        return item.id == id;
                    });
                    console.log(book)
                    this.id = book[0].id;
                    this.name = book[0].name;
                }
            }
        });
    </script>

6 删除图书

  <tbody>
          <tr :key='item.id' v-for='item in books'>
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <td>{{item.date}}</td>
            <td>
              <a href="" @click.prevent='toEdit(item.id)'>修改</a>
              <span>|</span>
               <!--  6.1 给删除按钮添加事件 把当前需要删除的书籍id 传递过来  --> 
              <a href="" @click.prevent='deleteBook(item.id)'>删除</a>
            </td>
          </tr>
</tbody>
  <script type="text/javascript">
    /*
      图书管理-添加图书
    */
    var vm = new Vue({
      methods: {
        deleteBook: function(id){
          // 删除图书
          #// 6.2 根据id从数组中查找元素的索引
          // var index = this.books.findIndex(function(item){
          //   return item.id == id;
          // });
          #// 6.3 根据索引删除数组元素
          // this.books.splice(index, 1);
          // -------------------------
         #// 方法二:通过filter方法进行删除
        
          # 6.4  根据filter 方法 过滤出来id 不是要删除书籍的id 
          # 因为 filter 是替换数组不会修改原始数据 所以需要 把 不是要删除书籍的id  赋值给 books 
          this.books = this.books.filter(function(item){
            return item.id != id;
          });
        }
      }
    });
  </script>

常用特性应用场景

1 过滤器

 <tr :key='item.id' v-for='item in books'>
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <!-- 1.3  调用过滤器 -->
            <td>{{item.date | format('yyyy-MM-dd hh:mm:ss')}}</td>
            <td>
              <a href="" @click.prevent='toEdit(item.id)'>修改</a>
              <span>|</span>
              <a href="" @click.prevent='deleteBook(item.id)'>删除</a>
            </td>
</tr>

<script>
        #1.1  Vue.filter  定义一个全局过滤器
        Vue.filter('format', function(value, arg) {
              function dateFormat(date, format) {
                if (typeof date === "string") {
                  var mts = date.match(/(\/Date\((\d+)\)\/)/);
                  if (mts && mts.length >= 3) {
                    date = parseInt(mts[2]);
                  }
                }
                date = new Date(date);
                if (!date || date.toUTCString() == "Invalid Date") {
                  return "";
                }
                var map = {
                  "M": date.getMonth() + 1, //月份 
                  "d": date.getDate(), //日 
                  "h": date.getHours(), //小时 
                  "m": date.getMinutes(), //分 
                  "s": date.getSeconds(), //秒 
                  "q": Math.floor((date.getMonth() + 3) / 3), //季度 
                  "S": date.getMilliseconds() //毫秒 
                };
                format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
                  var v = map[t];
                  if (v !== undefined) {
                    if (all.length > 1) {
                      v = '0' + v;
                      v = v.substr(v.length - 2);
                    }
                    return v;
                  } else if (t === 'y') {
                    return (date.getFullYear() + '').substr(4 - all.length);
                  }
                  return all;
                });
                return format;
              }
              return dateFormat(value, arg);
            })
#1.2  提供的数据 包含一个时间戳   为毫秒数
   [{
          id: 1,
          name: '三国演义',
          date: 2525609975000
        },{
          id: 2,
          name: '水浒传',
          date: 2525609975000
        },{
          id: 3,
          name: '红楼梦',
          date: 2525609975000
        },{
          id: 4,
          name: '西游记',
          date: 2525609975000
        }];
</script>

2 自定义指令

<!-- 2.2  通过v-自定义属性名 调用自定义指令 -->
<input type="text" id="id" v-model='id' :disabled="flag" v-focus>

<script>
    # 2.1   通过Vue.directive 自定义指定
    Vue.directive('focus', {
      inserted: function (el) {
        el.focus();
      }
    });

</script>

3 计算属性

 <div class="total">
        <span>图书总数:</span>
        <!-- 3.2 在页面上 展示出来 -->
        <span>{{total}}</span>
</div>

  <script type="text/javascript">
    /*
      计算属性与方法的区别:计算属性是基于依赖进行缓存的,而方法不缓存
    */
    var vm = new Vue({
      data: {
        flag: false,
        submitFlag: false,
        id: '',
        name: '',
        books: []
      },
      computed: {
        total: function(){
          // 3.1  计算图书的总数
          return this.books.length;
        }
      },
    });
  </script>

上一篇 下一篇

猜你喜欢

热点阅读