Vue(一)---指令

190 阅读10分钟

介绍

Vue是一款渐进式JavaScript框架。特点:其一,遵循遵循MVVM模式,无需操作DOM来更新视图。(我们只需要关心如何获取数据,如何处理数据,将处理好的数据交给vue,Vue会自动将数据渲染到页面中);其二,编码简洁 体积小,运行效率高;可以轻松引入一些第三方库和vue插件。

渐进式

  • vue-cli: vue脚手架
  • vue-resource(axios): ajax请求
  • vue-router: 路由
  • vuex: 状态管理
  • vue-lazyload: 图片懒加载
  • vue-scroller: 页面滑动相关
  • mint-ui: 基于vue的组件库(移动端)
  • element-ui: 基于vue的组件库(PC端)

你可以一步一步有阶段性地来使用vue,如果是简单应用,只需要一个核心课就可以,100KB大小。复杂应用可以按需加载各种各样的插件。这就是渐进式

使用

  1. 下载安装:

    第一种:传统的引入方式,下载vue.js文件,在页面中引入

    第二种:使用vue-cli脚手架导入使用。(之后再使用)

    目前我们以第一种方式为主。

    cdn:www.bootcdn.cn/vue/2.6.14/

  2. 将vue.js引入到当前页面

  3. 创建vue实例对象。

  4. 指定vue实例对象的控制区域(挂载)

  5. 指定vue实例对象的配置信息

   <div id="app">
     <input type="text" v-model="msg">
     {{msg}}
   </div>
   //引入Vue本地文件
  <script src="vue.js"></script>
  <script>
  //创建实例
    const vm = new Vue({
  // el:可以是css选择器,也可以是元素节点
      el:"#app",
  //数据
      data:{
        msg:"学习Vue的第一天"
      }
    });
  </script>

插值表达式

在上面的例子中我们看到有这样一个东西 {{msg}},这样的一个东西叫做插值表达式基本语法是:{{数据/表达式}},实现的功能是向页面渲染数据或表达式的结果(表达式一般是简单的表达式,如果是逻辑较为复杂的表达式我们后面会有其他方式代替,所以这里的表达式指的是简单的表达式)

  • 简单表达式:算数运算符、调用数学方法Math.XXX Dats.XXX 、三元表达式。

数据绑定(浅析)

在介绍Vue的时候我们说它是遵循MVVM模式,那么这个模式究竟是什么呢?

MVVM设计模式: Model-view-viewModel 简写

  • Model:模型 可以理解为后端传递过来的数据。
  • view:视图 我们所看到的页面(DOM元素)
  • VM:viewmodel 视图模型 它是连接view和model的桥梁。
 vm有两个方向:
        1.将模型转化为视图,将后端传递过来的数据渲染到我们所看到的的页面。
        2.将视图转化为模型。 将看到的页面转为后端的数据。
  数据单向绑定:
        将model绑定到view,用js代码更新数据时,view会自动更新。不需要额外的DOM操作。
        常见的单向绑定:{{}}  v-bind
  数据的双向绑定:
        将model绑定到view的同时,也将view 绑定到model。
        在input  textarea等表单元素上使用v-model指令来进行双向数据绑定。

数据绑定原理: 上面简单介绍了数据绑定,那么当我们的数据变化的时候页面是如何知道数据变化了呢?如何做到了及时的将最新的数据渲染到页面上呢?

其实,当一个数据变化时,Vue通过Object.definePropety可以监听到属性值的变化,它对应的有两个方法:set()get(),前者是当我们设置数据的值的时候会自动调用,后者是当我们获取数据的时候会自动触发。这样就实现了数据的绑定。

 // <div id="app"></div>  html部分
 //<input type="text" id="inp">  html部分
 
 
 //定义一个空对象
 var book = {};
    //定义一个变量,存放 书名
    var bookName = '';
    Object.defineProperty(book,"name",{
      //给book的name属性设置值的时候,会自动调用
      set(value){
        //value 就是设置的值。
        bookName = value;
        console.log(`你取了一个书名,叫做${value}`);
        //将值渲染在页面上。
        document.getElementById("app").innerHTML = value;
      },
      //获取book的name属性的属性值的时候,会自动调用。
      // 该方法的返回值就是 调用该属性时获取的值。
      get(){
        //在这里无法直接获取set函数设置的值,所以需要通过一个外部的变量来保存。
        return `《${bookName}》`;
      }
    })
    // 当视图更新时,vue如何知道? 
    // 根据输入框的input事件来监听 视图的更新
    let inp = document.getElementById("inp");
    inp.oninput = function(){
      book.name = this.value;
    }

指令操作

指指令是Vue模板中最常用的一项功能,是以v-开头的自定义标签属性。

V-text

将data中的数据显示在页面中,除了使用双大括号{{}}来进行插值外,还可以使用v-text

<p v-text="msg"></p>
<!-- 和下面的一样 -->
<p>{{ message }}</p>
new Vue({
    el:"#app",
    data : {
        message : "学习Vue使我快乐!"
    }
 })

V-text插值表达式的区别:v-text会覆盖元素中原本的内容,插值表达式{{ }}只会替换自己的这个占位符,不会把整个元素内容替换。

<p v-text='text'>vue</p> <!-- vue会被覆盖,结果为 hello  -->
<p>{{text}},vue</p><!--结果为 hello,vue  -->

V-html(了解)

解析html代码可以将标签解析出来,但是官网是不建议在网站上动态渲染html

<div id="app" v-html="msg">  
</div>
<script>
    let vue = new Vue({
        el: '#app',
        data: {
            msg: "<h1>hello,vue</h1>"
        }
    });
</script>

V-bind

动态更新html元素上的属性。比如:ID、Class、href、src等。简写方式为‘ V-bind ’等价于‘ :’

<img v-bind:src="url">//等价于 <img :src="url">
var app = new Vue({
	el:"#app",
    data:{
        url:"xxx.png"
    }
})

V-on(事件绑定)

简略写法V-on:事件类型等价于@事件类型

<button v-on:click="myFn()">我是按钮</button>//等价于<button @click="myFn()">我是按钮</button>
let vue = new Vue({
    el: '#app',
    //这里我们需要在methods方法最终定义事件执行的操作响应
    methods: {
    //事件执行的操作 myFn():可以传入参数
        myFn(){
            alert('你点击了按钮')
        }
    }
});

注意:如果我们在绑定的回调函数中需要用到data中的数据,需要加上this,指的是当前的data中的某一条数据。

上面我们说myFn()中可以传入参数,那我们尝试一下用这个特性来阻止a标签的默认行为。这里vue为我们提供了一个特殊变量$event,用于访问原生DOM事件。

<a href="http://www.baidu.com" @click="myFn('禁止跳转',$event)">我是按钮</a>
let vue = new Vue({
    el: '#app',
    methods: {
        myFn(msg,event){
            //阻止默认事件
            event.preventDefault();
            console.log(msg)
        }
    }
});

修饰符:

上面的案例,如果我们遇到需要组织默认行为的时候都那样去写会不会太麻烦了?Vue为我们提供了一个新的东西修饰符

  • 使用:在@绑定的事件后添加小圆点.,再跟一个后缀来使用修饰符。

常见的修饰符:

  • stop:阻止冒泡
  • prevent:阻止浏览器默认行为
  • once:只触发一次
  • 按键序号: 键盘修饰符 阻止冒泡:可以分别设置类a、b、c为盒子,包裹关系,来看效果
<div class="a" @click="myFn1">
    <div class="b" @click.stop="myFn2">
        <div class="c" @click="myFn3"></div>
    </div>
</div>
 let vue = new Vue({
        el: '#app',
        methods: {
            myFn1(){
                console.log("大盒子");
            },
            myFn2(){
                console.log("中盒子");
            },
            myFn3(){
                console.log("小盒子");
            }
        }
    });

键盘事件:

<!-- 只有在keycode是13,也就是回车键时才会调用myFn函数 -->
<input @keyup.13="myFn">

V-if

条件渲染:如果v-if取值是true就渲染元素, 如果为false就不渲染元素,v-if可以从模型中获取数据,也可以直接赋值一个表达式。

<p v-if="show">显示</p>
<p v-if="age >= 18">你已经成年了</p>
let vue = new Vue({
    el: '#app',
    data: {
        show: true,
        age: 17,
    }
});

v-else指令

v-else可以和v-if指令配合使用, 当v-if不满足条件时就执行v-else就显示v-else中的内容

<p v-if="age >= 18">你已经成年了</p>
<p v-else>你还是未成年</p>
let vue = new Vue({
    el: '#app',
    data: {
        age: 17,
    }
});

v-else-if指令

v-else-if可以和v-if指令配合使用, 当v-if不满足条件时就依次执行后续v-else-if, 哪个满足就显示哪个。

<p v-if="state==0">未付款</p>
<p v-else-if="state==1">待发货</p>
<p v-else-if="state==2">待签收</p>
<p v-else-if="state==3">已签收</p>
<p v-else>未知</p>
let vue = new Vue({
    el: '#app',
    data: {
        state: 
        0,
    }
});

小技巧:我们可以在浏览器扩展里边下载一个扩展名字为:vue-Devtools 来调试。

v-show

条件渲染指令,如果表达式结果为真,则显示该元素,如果为假,则隐藏该元素(需要是已经存在的Dom)

<p v-show="show">显示</p>
<p v-show="age >= 18">你可以正常进入网吧了!</p>
let vue = new Vue({
    el: '#app',
    data: {
        show: true,
        age: 17,
    }
});

V-ifV-show比较:

  • v-if值为false时不会创建元素,v-show值为false时会创建元素只是设置displaynone
  • 频繁切换显示或隐藏元素使用V-show,其他特殊情况可以使用V-if

V-for

列表渲染指令,当需要将一个数组遍历或枚举一个对象的属性时,我们就可以使用v-for指令。类似于for in循环。

<div id="app">
    <ul>
        <li v-for="user in users">{{user.name}}</li>
    </ul>
</div>
let vue = new Vue({
    el: '#app',
    data: {
        users:[
            {name:"张三"},
            {name:"李四"},
            {name:"王五"}
        ]
    }
});

v-for还可以传第二个参数作为当前元素的索引

<div id="app">
    <ul>
        <li v-for="(user,index) in users">{{index}}-{{user.name}}</li>
    </ul>
</div>

遍历对象属性时,有两个可选参数,分别表示键名和索引。

<li v-for="(value,key,index) in person">{{index}}----{{key}}-----{{value}}</li>

数组: Vue 的核心是数据与视图的双向绑定,当我们修改数组时,Vue会检测到数据变化,所以用v-for 渲染的视图也会立即更新。

会修改原数组的方法:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort() 排序
  • reverse() 转置 不会修改源数组的数组方法:
  • filter() 过滤
  • concat() 合并
  • slice 截取

数组的更新需注意:

通过索引直接设置数组的元素,是不能被vue监听到的,因为vue监听的是数组的变化,不会监听到数组内部

所以,对于数组的有些方法并不会修改原数组的,使用这些方法并不会让视图更新。(如:filter 过滤 concat 合并 slice截取)

解决方法:使用Vue内置的set方法 Vue.set(要设置的数组,要修改的元素的索引,要修改的内容)

<div id="app">
    <button @click="fn">修改数据</button>
    <ul>
      <li v-for="(item,index) in users" v-bind:data="item">{{index}}--{{item}}</li>
    </ul>
 </div>
 new Vue({
      el: "#app",
      data: {
        users: ["宋江", '卢俊义', '公孙胜', '吴用'],
        msg: "懂得都懂",
        num: 5,
        person: {
          name: "张三",
          age: 20,
          habby: "蹲监狱"
        }
      },
      methods: {
        fn() {
          // this.users.reverse()
          // this.users[3] = '关胜';   并不能使改变后的数据渲染到页面
          Vue.set(this.users, 3, "关胜")
        }
      }
    })

需要注意的是,当我们使用V-for指令遍历一个数组中包含多个对象的时候一般要给每一个节点添加一个唯一的标识key,这一点是非常重要的。 如下:

  <div id ="app">
    <form>
      <p>书名:<input type="text" v-model="bookName"></p>
      <p><input type="submit" value="添加" @click.prevent="add"></p>
    </form>
    <ul>
      <li v-for="(item,index) in books" :key="item.id"><input type="checkbox"> {{item.name}}  <button @click="del(index)">删除</button></li>
    </ul>
  </div>
 var vm = new Vue({
    el: '#app',
    data: {
      id:4,
      bookName:"",
      books:[
        {id:1,name:"明克街13号"},
        {id:2,name:"我的云养女友"},
        {id:3,name:"星门"}
      ]
    },
    methods: {
      //点击 添加 按钮触发add函数
      add(){
      //生成一个新的book对象
        let book = {id:this.id,name:this.bookName};
      //添加到books中, books一旦变化,页面会自动更新。
        this.books.push(book);
        this.bookName = "";
      },
      del(i){
      //实现删除功能
        this.books.splice(i,1);
      }
    }
   });

补充:虚拟Dom

Vue.js 2.0引入Virtual DOM,初始渲染速度提升了2-4倍,并大大降低了内存消耗。

简单来说,可以把Virtual DOM 理解为一个简单的JS对象,并且最少包含标签名( tag)、属性(attrs)和子元素对象( children)三个属性。

vue为了提高效率,在更新已渲染过的元素列表时,会采用“就地复用”策略。

所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。

--如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。
--而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
--如果你用 index 作为 key,那么在删除第二项的时候,index 就会从 1 2 3 变成 1 2(因为 index 永远都是连续的,所以不可能是 1 3),那么 Vue 依然会认为你删除的是第三项。也就是会遇到上面一样的 bug。所以,永远不要用 index 作为 key。

V-once

定义它的元素或组件只渲染一次,包括元素或组件的所有子节点。首次渲染后,不再随数据的变化重新渲染,将被视为静态内容。

<div id="app">
    <p v-once>原始数据: {{ name }}</p>
    <p>当前数据: {{ name }}</p>
</div>
let app = new Vue({
    el: '#app',
    data: {
        name: "zhangsan",
    }
});
//当我们修改数据的时候就可以看到效果:app.name="onion",这条信息并为渲染出来