初识 Vue.js

989次阅读  |  发布于3年以前

Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。

Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

那么该如何在页面上引入Vue?又该如何使用Vue进行开发呢?我们接下来一起初步认识一下Vue。首先创建一个html页面,并引入Vue.js:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

你也可以将vue.js文件直接下载到本地,然后引入。

接下来看一段示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
    <div id="app">
        <!-- {{}} 可以取出data定义的数据 -->
        <p>{{msg}}</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app = new Vue({
            el:'#app',
            data:{
                msg:'Hello Vue!'
            }
        });
    </script>
</body>
</html>

创建Vue实例,其中的el指定需要控制的DOM,这里指定为#app,则id为app的div范围是Vue的控制范围;其次是data,它可以定义该范围内使用的数据,形式为键值对,当然Vue实例中可以定义的内容远不止如此,但我们先来看看这段代码的效果:

Vue指令

Vue提供了一种非常简便的方式来控制和操作DOM,那就是Vue指令,Vue提供了各式各样的指令,我们先来了解比较常用的几个指令。

v-cloak

在刚才我们使用了 {{}} 符号来取出data中定义的数据,这一符号称为 插值表达式 ,然而这种方式取出数据有一个弊端,当网络出现波动时,页面上会将插值表达式显示出来而非显示真正的数据:

这显然会给用户造成不好的体验,为此,我们可以使用v-cloak指令来解决这一问题:

<!DOCTYPE html>
<html lang="en">
<head>
</head>
<style>
    [v-cloak] {
        display: none;
    }
</style>
<body>
    <div id="app">
        <p v-cloak>{{msg}}</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app = new Vue({
            el:'#app',
            data:{
                msg:"Hello Vue!"
            }
        });
    </script>
</body>
</html>

若如此做,则在msg数据被取到之前,v-cloak修饰的DOM元素将会被隐藏,这样便解决了插值表达式的闪烁问题。

v-text & v-html

这两个指令都是用于显示数据的:

<p v-text="msg"></p>
<p v-html="msg"></p>

它们在显示效果上没有什么不同:

但这两个指令之间还是有一定区别的。首先v-text和v-html指令都不存在闪烁问题,其次它们是将数据直接覆盖到DOM上,所以DOM原先的数据就会消失;但是v-html指令还能够将数据中的标签进行解析,而v-text不能:

<div>
  <p v-text="msg"></p>
  <p v-html="msg"></p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el:'#app',
    data:{
      msg:"<h1>Hello Vue!</h1>"
    }
  });
</script>

显示效果:

v-bind

有时候v-text和v-html指令都不能满足我们的需求,比如提供一个按钮的提示信息,这个时候我们可以借助v-bind指令:

<div id="app">
  <input type="button" v-bind:title="msg" value="按钮"/>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el:'#app',
    data:{
      msg:"这是一个按钮"
    }
  });
</script>

效果如下:

v-bind指令用于绑定DOM属性,也就是说,只要是DOM的属性,它都能够直接进行绑定,比如input框的value属性:

<input type="button" v-bind:title="msg" v-bind:value="msg"/>

效果如下:

v-bind也能够绑定样式:

<style>
  .red {
    color: red;
  }
  .thin {
    font-weight: 200;
  }
</style>
<body>
  <div id="app">
    <h1 v-text="msg" v-bind:class="['red','thin']"></h1>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var app = new Vue({
      el: '#app',
      data: {
        msg: 'Hello Vue!'
      },
    });
  </script>

通过v-bind进行样式绑定时,有几种方式,这便是其中的一种,通过数组绑定,注意数组中的样式名必须用引号包含。我们还可以通过对象进行绑定:

<div id="app">
  <h1 v-text="msg" v-bind:class="{red:true,thin:true}"></h1>
</div>

但这种方式的样式名后面必须跟上 :true:false ,所以我们可以通过在data中定义一个flag进行动态设置:

<div id="app">
  <h1 v-text="msg" v-bind:class="{red:flag,thin:flag}"></h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      msg: 'Hello Vue!',
      flag: true
    },
  });
</script>

此时flag就能够控制样式是否进行显示。 v-bind指令可以简写为 : ,例如:

<input type="button" :title="msg" :value="msg"/>

v-for

该指令用于循环操作:

<div id="app">
  <p v-for="item in array">
    {{item}}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      array: [1, 2, 3, 4, 5]
    },
  });
</script>

v-for指令语法为 item(为数组中的每一项取一个名字) in list(待遍历的数组名) ,然后item就是数组中的每一个元素,效果如下:

有时候我们需要获得当前元素的索引值,可以这样写:

<p v-for="(item,index) in array">
  {{index}} ---- {{item}}
</p>

对于较为复杂的数组,v-for当然也能够轻松进行遍历:

<div id="app">
  <p v-for="(user,index) in array">
    索引值:{{index}}--id:{{user.id}}--name:{{user.name}}--age:{{user.age}}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      array:[
        {id:1,name:'张三',age:20},
        {id:2,name:'李四',age:21},
        {id:3,name:'王五',age:22},
      ]
    },
  });
</script>

效果如下:

v-for指令还能够遍历对象:

<div id="app">
  <p v-for="(value,key,index) in user">
    索引:{{index}}---{{key}}:{{value}}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      user: { id: 1, name: '张三', age: 20 }
    }
  });
</script>

效果如下:

在使用v-for指令时需要注意一点,在Vue2.2.0之后的版本,当在组件中使用v-for时,必须携带key属性,有必要解释一下它的作用。当Vue用v-for正在更新已经渲染过的元素列表时,默认使用的是 就地复用 策略,如果数据项的顺序被改变,Vue将简单复用此处每个元素,而不是移动DOM中的元素来匹配顺序;

为了给Vue一个提示,以便Vue能够跟踪每个节点的身份,从而复用和重新排序现有的元素,我们需要为每项提供一个唯一属性key:

<div id="app">
  <div>
    <label>id:</label>
    <input type="text" v-model="id">
    <label>name:</label>
    <input type="text" v-model="name">
    <input type="button" value="添加" @click="add">
  </div>
  <p v-for="user in array">
    <input type="checkbox">
    {{user.id}}--{{user.name}}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      id: '',
      name: '',
      array: [
        { id: 1, name: '张三' },
        { id: 2, name: '李四' },
        { id: 3, name: '王五' }
      ]
    },
    methods: {
      add() {
        this.array.unshift({ id: this.id, name: this.name });
      }
    },
  });
</script>

该页面用于实现数据的添加操作,效果如下:

当上方填入数据并点击添加时会将数据在下面的列表中展示,然而这段程序有些许问题:

当选中3号数据,并添加4号数据时,结果如下:

选中的数据被修改为了2号,这就是没有指定key的后果,我们只需在遍历的时候为key设置一个唯一的属性即可:

<p v-for="user in array" :key="user.id">
  <input type="checkbox">
  {{user.id}}--{{user.name}}
</p>

需要注意key只能设置string或者number类型的值。

v-if & v-show

这两个指令均用于控制DOM的显示与隐藏:

<div id="app">
  <p v-if="flag">v-if</p>
  <p v-show="flag">v-show</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      flag: true
    }
  });
</script>

效果如下:

咋一看,两者好像没有什么区别,但是查看源代码:

当我们将flag设置为false时,v-if指令会直接将DOM元素删除掉,而v-show指令只是将display属性置为none,隐藏了DOM。

v-on

该指令用于事件绑定,比如:

<div id="app">
  <input type="button" value="按钮" v-on:click="show"/>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el:'#app',
    data:{
    },
    methods: {
      show(){
        alert("点击了按钮");
      }
    }
  });
</script>

通过v-on可以绑定事件,并在v-on后面指定需要绑定的事件,click即为点击事件,其值为需要触发的函数名,该函数必须写在Vue实例的methods属性中。若是想要绑定其它事件,例如鼠标移除入事件:

<input type="button" value="按钮" v-on:mouseover="show"/>

v-click也可以简写为 @

<input type="button" value="按钮" @click="show"/>

事件修饰符

Vue提供了一些事件修饰符来应对事件中遇到的一些常见问题,种类如下:- stop:阻止事件冒泡

stop

<div id="app" style="width: 150px;height: 150px;background-color: red;" @click="divClick">
  <input type="button" value="按钮" @click="btnClick"/>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {

    },
    methods: {
      divClick(){
        alert("点击了DIV");
      },
      btnClick(){
        alert("点击了按钮");
      }
    },
  });
</script>

在该页面中,有一个按钮存在于div中:

由于事件冒泡机制,在点击按钮时,会先触发按钮的事件,还会触发div的点击事件,但有些场景下,我们并不想在点击的按钮时触发父标签的事件,为此,可以使用stop来阻止事件的冒泡:

<input type="button" value="按钮" @click.stop="btnClick"/>

prevent

<div id="app">
  <a href="http://www.baidu.com" @click="aClick">百度一下</a>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {

    },
    methods: {
      aClick(){
        alert("点击了超链接");
      }
    },
  });
</script>

在该页面中有一个超链接,点击它会跳转至百度首页,然而该超链接绑定了一个点击事件,但因为超链接的跳转性质,使得点击事件无法触发,为此,可以使用prevent来阻止超链接的默认行为:

<a href="http://www.baidu.com" @click.prevent="aClick">百度一下</a>

capture 仍然是对于第二个例子:

通过capture能够修改事件监听器为捕获模式,默认是冒泡机制,如果使用了capture,可以使事件从外向里传递:

<div id="app" style="width: 150px;height: 150px;background-color: red;" @click.capture="divClick">
  <input type="button" value="按钮" @click="btnClick" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {

    },
    methods: {
      divClick() {
        alert("点击了DIV");
      },
      btnClick() {
        alert("点击了按钮");
      }
    },
  });
</script>

此时点击按钮将会先弹出点击了DIV,然后弹出点击了按钮。

self

<div id="app" style="width: 150px;height: 150px;background-color: red;" @click.self="divClick">
  <input type="button" value="按钮" @click="btnClick" />
</div>

self表示只有自身触发的事件才会执行回调方法,比如该页面中,如果点击按钮,则会触发按钮的点击事件,由于事件的冒泡机制,外层的div也会触发点击事件,但因为外层div使用了self,不是自己触发的事件,所以div的点击事件不会被触发。

once

该修饰符能保证事件只触发一次:

<div id="app">
  <a href="http://www.baidu.com" @click.prevent.once="aClick">百度一下</a>
</div>

事件修饰符能够组合使用,在该页面中的超链接被设置为阻止默认行为一次,则第一次点击会触发aClick点击事件,接下来再点击就会跳转至百度首页。

双向数据绑定

通过前面的学习,我们了解到v-text、v-html、v-bind能够将data中的数据显示到DOM中,然而这只是一个单向数据绑定的过程,即:data中的数据被绑定到了DOM中,而DOM中数据的改变并不能影响data中的数据,例如:

<div id="app">
  <input type="text" :value="msg"/>
  <input type="text" :value="msg"/>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      msg: 'Hello Vue!'
    },
  });
</script>

效果如下:

两个input框均绑定了msg数据,但是这两个框内容的修改互不影响,为了实现数据的双向绑定,可以使用v-model指令:

<div id="app">
  <input type="text" v-model="msg"/>
  <input type="text" v-model="msg"/>
</div>

效果如下:

这两个输入框的值会同步更新,因为输入框内容的修改会影响到data中msg的值,这就是数据的双向绑定;但需要注意一点,v-model指令只能用于表单元素。

过滤器

现有一个显示日期的label:

<div id="app">
  <label>{{new Date()}}</label>
</div>

效果如下: 这显然不是一个友好的日期显示,为此,我们可以使用Vue提供的过滤器来格式化日期:

<div id="app">
  <label>{{new Date() | dateFormat}}</label>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
  // 定义全局的过滤器
  Vue.filter('dateFormat', function (dateStr) {
    // 根据时间字符串构建Date对象
    var dt = new Date(dateStr);
    // 获取年、月、日
    var year = dt.getFullYear();
    var month = dt.getMonth() + 1;
    var day = dt.getDate();
    // 格式化日期
    return `${year}-${month}-${day}`;
  });

  var app = new Vue({
    el: '#app',
    data: {
    }
  });
</script>

通过Vue.filter()定义全局的过滤器,提供两个参数,第一个参数为过滤器的名字,第二个参数为过滤器需要处理的逻辑代码,在该函数内正确处理日期并返回即可;然后在使用过程中需要注意,过滤器采用管道符 | 连接需要处理的数据,管道符后跟过滤器的名字,此时管道符前面的数据将会作为过滤器的处理函数的参数。

在调用过滤器进行处理时,也可以继续传入别的参数,比如:

<label>{{new Date() | dateFormat('yyyy-mm-dd')}}</label>
<script>
  Vue.filter('dateFormat', function (dateStr,pattern) {
    ......
  });
</script>

这种通过Vue.filter()的方式定义的过滤器为全局过滤器,是对所有的Vue实例均起作用的,当然了,我们还可以定义仅作用于当前Vue实例的私有过滤器:

<script>
  var app = new Vue({
    el: '#app',
    data: {
    },
    filters: {
      // 定义私有过滤器
      dateFormat: function (dateStr) {
        // 根据时间字符串构建Date对象
        var dt = new Date(dateStr);
        // 获取年、月、日
        var year = dt.getFullYear();
        var month = dt.getMonth() + 1;
        var day = dt.getDate();
        // 格式化日期
        return `${year}-${month}-${day}`;
      }
    }
  });
</script>

若是同时存在私有过滤器和全局过滤器,则默认使用私有过滤器(就近原则)。

按键修饰符

一般网站都具有回车确认填写信息的功能,我们来模拟一下:

<div id="app">
  <input type="text" v-model="msg" @keyup.enter="add">
  <p>{{result}}</p>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
  var app = new Vue({
    el: '#app',
    data: {
      msg: '',
      result:''
    },
    methods: {
      add(){
        this.result = this.msg;
      }
    },
  });
</script>

效果如下:

当在输入框输入内容并按下回车后,下方便会显示输入的内容,这是因为我们设置了输入框的键盘点击事件,而通过按键修饰符则可以精确控制键盘按下哪个键后会触发回调函数,比如这里的 .enter ,它表示回车键。其它的按键修饰符如下:

这些是Vue为方便开发,自己定义的一些常用修饰符,对于别的按键,我们只能用对应的关键字码进行设置:

<input type="text" v-model="msg" @keyup.113="add">

113对应按键 F2 ,此时点击F2就会触发回调函数。为了便于区分,我们也可以为这些关键字码设置别名:

<script>
  // 定义按键修饰符
  Vue.config.keyCodes = {
    "F1": 113,
  };
</script>

此时使用别名即可:

<input type="text" v-model="msg" @keyup.f2="add">

自定义指令

现有一个输入框:

<div id="app">
  <input type="text" id="it">
</div>

若是想在刷新页面后自动获取输入框的焦点,该如何实现呢?其实非常简单,可以调用输入框的 focus 函数:

<div id="app">
  <input type="text" id="it">
</div>

<script>
  document.getElementById('it').focus();
</script>

但Vue不推荐我们直接操作DOM,所以我们可以将其转化为自定义的指令:

<div id="app">
  <input type="text" v-focus>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  // 自定义指令
  Vue.directive('focus', {
    // 当指令绑定到指定元素上时调用此函数,只执行一次
    bind(el) { // el即为绑定该指令的元素

    },
    // 当元素插入到DOM时调用此函数,只执行一次
    inserted(el) {
      el.focus();
    },
    // 当元素更新时调用此函数,执行多次
    updated(el) {

    }
  });
</script>

这里需要注意,自定义指令通过 Vue.directive 进行设置,它需要两个参数,第一个参数为指令的名称,第二个参数为一个对象,在该对象内需要定义指令生效的三个周期函数,周期函数的入参中可以获取到绑定该指令的元素,然后调用 focus 获取焦点即可。 在使用该指令时也需要注意,必须在自定义的指令名前加上 v- 前缀。

那么自定义指令该如何实现传值呢:

<div id="app">
  <input type="text" v-color="'red'">
</div>

自定义一个v-color指令,并根据传递的参数值设置输入框的字体颜色, 实现如下:

<script>
  // 自定义指令
  Vue.directive('color', {
    // 当指令绑定到指定元素上时调用此函数,只执行一次
    bind(el,binding) { // el即为绑定该指令的元素
      el.style.color = binding.value;
    },
    // 当元素插入到DOM时调用此函数,只执行一次
    inserted(el) {
    },
    // 当元素更新时调用此函数,执行多次
    updated(el) {

    }
  });
</script>

通过周期函数的第二个参数 <span style="font-size: 15px;font-family: Optima-Regular, PingFangTC-light;">binding ,我们能够获取到很多信息,其中value属性即为指令设置的值,将该值设置到样式中即可。 刚才定义的是全局指令,我们也可以定义只属于某个Vue实例本身的私有指令,与过滤器类似,只需在Vue实例中定义即可:

<script>
  var app = new Vue({
    el: '#app',
    data: {
    },
    directives: {
      // 自定义私有指令
      'color': {
        // 当指令绑定到指定元素上时调用此函数,只执行一次
        bind(el, binding) { // el即为绑定该指令的元素
          el.style.color = binding.value;
        },
        // 当元素插入到DOM时调用此函数,只执行一次
        inserted(el) {
        },
        // 当元素更新时调用此函数,执行多次
        updated(el) {
        }
      }
    }
  });
</script>

Vue还提供了一种更简便的方式来自定义指令:

<script>
  Vue.directive('Vue', function (el,binding) {
    el.style.color = binding.value;
  });
</script>

但这种方式只会生效于bind和updated周期函数,它等同于将函数中的代码在bind和updated函数中均粘贴一份。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8