vue.js基础知识篇(1):简介、数据绑定、指令、计算属性、表单控件绑定和过滤器

目录第一章:vue.js是什么? 代码链接: http://pan.baidu.com/s/1qXCfzRI 密码: 5j79

第一章:vue.js是什么?

1.vue.js是MVVM框架

MVVM的代表框架是Angular.js,以及vue.js。

MVVM的view和model是分离的,View的变化会自动更新到ViewModel上,ViewModel的变化会自动同步到View上显示。这种自动同步依赖于ViewModel的属性实现了Observer。

2.它与angular.js的区别

相同点:都支持指令、过滤器和双向绑定,都不支持低端浏览器。

不同点:

(1)学习成本不一样,比如ng有依赖注入。

(2)性能上ng依赖对数据做脏检查,所以watcher越多越慢。vuel.js依赖于追踪的观察并且使用异步队列更新,所以数据都是独立触发的。

3.vue.js的安装

可以通过Script标签引入vue.js文件,可以通过npm安装。

4.第一个hello world程序

(1)通过npm安装vue的使用

step1:

$ npm init
$ npm install  vue --save-dev

step2:

//app.js代码

var vue=require("vue");

console.log(vue);

运行,

$ node app.js

OK。

(2)直接通过script标签引入vuel.js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue.js</title>
</head>
<body>
   <div id="didi-navigator">
       <ul>
           <li v-for="tab in tabs">
               {{tab.text}}
           </li>
       </ul>
   </div>
   <script src="js/vue.js"></script>
   <script>
       new Vue({
           el:"#didi-navigator",
           data:{
               tabs:[
                   {text:"巴士"},
                   {text:"快车"},
                   {text:"顺风车"},
                   {text:"出租车"},
                   {text:"代驾"}
               ]
           }
       });
   </script>
</body>
</html>

第一个hello world程序

浏览器的显示效果是

第2章:数据绑定

1.语法

(1)类似angularjs的{{}},插值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="app">
        <div>Text:{{text}}</div>
    </div>
    <script src="js/vue.js"></script>
    <script>
        new Vue({
            el:"#app",
            data:{
                text:"我是文本"
            }
        })
    </script>
</body>
</html>

可以看到如果text的值发生改变,文本中的值也会联动的变化。(竟然难过:(。书上说的使用星号实现单次渲染、3个大括号填入HTML片段,用1.0.24版本的控制台报错,说是不合法的表达式,说明这两种怪异的语法已经过时了。)

注意:vue指令和自身的特性是不可以插值的。

(2)表达式

表达式由js表达式和过滤器构成。过滤器本质是一个函数,要使用过滤器,要先写过滤符(|)。

关于大写过滤器的例子。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
     <title>Title</title>

</head>
<body>
<div id="app">
    <div>{{msg|uppercase}}</div>
</div>
<script src="js/vue.js"></script>
<script>
    var vm=new Vue({
        el:"#app",
        data:{
            msg:"eeeeeeeqeeecfff"
        }
    })
</script>
</body>
</html>

显示效果:

关于过滤器的到底有哪些内置的,可以通过查看源代码获取到。搜索"var filters={",就能找到源代码了。

(3)指令

指令是带有v-前缀的特殊特性,其值限定为绑定表达式,也就是js表达式和过滤器,那么当表达式的值发生变化时,这个变化也会反映到DOM上。

2.可以通过Vue.config配置数据绑定的语法

vue.js中数据绑定的语法被设计为可配置。

//delimiters搜索源码

var delimiters = [‘{{‘, ‘}}‘];
var unsafeDelimiters = [‘{{{‘, ‘}}}‘];
//...............
delimiters: { /**
                   * Interpolation delimiters. Changing these would trigger
                   * the text parser to re-compile the regular expressions.
                   *
                   * @type {Array<String>}
                   */

      get: function get() {
        return delimiters;
      },
      set: function set(val) {
        delimiters = val;
        compileRegex();
      },
      configurable: true,
      enumerable: true
    },

源代码说的很清楚,configurable是可配置的。

核心代码就一句:Vue.config.delimiters=["<%","%>"]。delimiters是config对象的属性,规定了默认的文本插值的分隔符。例子如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="app">
    <div><%msg%></div>
</div>
<script src="js/vue.js"></script>
<script>
    Vue.config.delimiters=["<%","%>"]
    var vm=new Vue({
        el:"#app",
        data:{
            msg:"eeeeeeeqeeecfff"
        }
    })
</script>
</body>
</html>

成功!

第三章:指令

1.语法

指令以v-打头,它的值限定为绑定表达式,它负责的是按照表达式的值应用某些行为到DOM上。

内部指令有v-show,v-else,v-model,v-repeat,v-for,v-text,v-el,v-html,v-on,v-bind,v-ref,v-pre,v-cloak,v-if。

2.内部指令

(1)控制元素的显示与否:v-if,v-show、v-else

v-if是真实的条件渲染,根据表达式的true/false在DOM中生成或移除一个元素。

第一,这个指令是惰性的,初始条件为false,那么什么都不做,直到条件第一次会真时才开始局部编译(编译会被缓存起来)。

第二,它支持template包装元素,所以可以对多个元素进行切换(查看“v-if与v-show的使用”代码)。

v-show是简单的基于css切换,当为false时,会看到对应的元素多了一个内联样式"style=display:none"。它不支持template语法。

比较而言,v-if有更高的切换消耗,v-show有更高的初始渲染消耗。那么如果需要频繁的切换,则使用v-show较好。如果运行时条件不大可能改变,则使用v-if较好。

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>v-if与v-hide</title>
 6 </head>
 7 <body class="native">
 8     <div id="example">
 9         <p v-if="greeting">Hello</p>
10         <template v-if="ok">
11             <h1>我是标题</h1>
12             <p>我是段落1</p>
13             <p>我是段落2</p>
14         </template>
15         <p v-show="greeting">Hello2</p>
16     </div>
17 <script src="js/vue.js"></script>
18 <script>
19     var exampleVM2=new Vue({
20         el:"#example",
21         data:{
22             greeting:false,
23             ok:true
24         }
25     })
26 </script>
27 </body>
28 </html>

v-if与v-show的使用

效果如图

v-else必须跟着v-if,充当else功能,相当于一个反义词的意思。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>v-else</title>
</head>
<body class="native">
<div id="example">
    <p v-if="ok">我是对的</p>
    <p v-else="ok">我是错的</p>
</div>
<script src="js/vue.js"></script>
<script>
    var exampleVM2=new Vue({
        el:"#example",
        data:{
            ok:false
        }
    })
</script>
</body>
</html>

v-else的使用

(2)v-model

v-model用在input、select、text、checkbox、radio表单控件元素上创建双向数据绑定。根据控件类型v-model自动选取正确的方法更新元素。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>v-else</title>
</head>
<body class="native">
<div id="example">
     <form>
         姓名:
         <input type="text" v-model="data.name" placeholder="">
         <br/>
         性别:
         <input type="radio" id="man" value="One" v-model="data.sex">
         <label for="man">男</label>
         <input type="radio" id="woman" value="Two" v-model="data.sex">
         <label for="woman">女</label>
         <br/>
         兴趣:
         <input type="checkbox" id="book" value="book" v-model="data.interest">
         <label for="book">阅读</label>
         <input type="checkbox" id="swim" value="swim" v-model="data.interest">
         <label for="book">阅读</label>
         <input type="checkbox" id="game" value="game" v-model="data.interest">
         <label for="game">游戏</label>
         <input type="checkbox" id="song" value="song" v-model="data.interest">
         <label for="song">唱歌</label>
         <br/>
         身份:
         <select v-model="data.identity">
             <option value="teacher" selected>教师</option>
             <option value="doctor" >医生</option>
             <option value="lawyer" >律师</option>
         </select>
     </form>
</div>
<script src="js/vue.js"></script>
<script>
    var vm=new Vue({
        el:"#example",
        data:{
            data:{
                name:"",
                sex:"",
                interest:[],
                identity:""
            }
        }
    })
</script>
</body>
</html>

无一例外,表单元素的值使用value属性定义,v-model定义数据属性,其中checkbox是多选,所以是数组。

除基本用法外,v-model指令有3个参数。

(1)number

代码演示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>v-else</title>
</head>
<body class="native">
<div id="example">
    <form>
        <h5>1.字符串形式的累加</h5>
       <input type="text"  id="age" v-model="age">
        <span>大6岁:{{age+3}}</span>
        <h5>2.数字类型的加法</h5>
       <input type="text"  number id="age2" v-model="age2">
        <span>大6岁:{{age2+6}}</span>
    </form>
</div>
<script src="js/vue.js"></script>
<script>
    var vm=new Vue({
        el:"#example",
        data:{
        }
    })
</script>
</body>
</html>

显示效果:

(2)lazy

默认情况下,v-model在input事件中同步输入框的值与数据。当添加了lazy属性时,要等到change事件发生后才会将数据更新掉。那么什么是change事件呢。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>v-model</title>
</head>
<body class="native">
<div id="example">
    <form>
        <h5>1.默认情况下,</h5>
        <input  v-model="msg" type="text" placeholder="" />
        <br/>
        {{msg}}
        <h5>2.lazy修饰词</h5>
        <br/>
        <input  v-model="msg2" type="text" placeholder="" lazy/>
        <br/>
        {{msg2}}
    </form>
</div>
<script src="js/vue.js"></script>
<script>
    var vm=new Vue({
        el:"#example",
        data:{
            msg:"1.内容是在change事件后才改变的",
            msg2:"2.内容是在change事件后才改变的"
        }
    })
</script>
</body>
</html>

首先,看默认情况。也是我们平常看到的样子。当我们输入的同时,数据的值同时被更新掉。

那么,lazy又是怎样的情况呢?

当只是输入的时候,由于lazy的作用,数据并没有更新。

当输入事件结束,点击其他地方,input框失去焦点,那么数据被更新掉了。

(3)debounce

用来设置延时同步的,以毫秒为单位,那就比lazy更加精确。要更新,需要一个等待时间咯。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>v-model</title>
</head>
<body class="native">
<div id="example">
    <form>
        <h5>1.默认情况下,</h5>
        <input  v-model="msg" type="text" placeholder="" />
        <br/>
        {{msg}}
        <h5>2.lazy修饰词</h5>
        <input  v-model="msg2" type="text" placeholder="" lazy/>
        <br/>
        {{msg2}}
    </form>
</div>
<script src="js/vue.js"></script>
<script>
    var vm=new Vue({
        el:"#example",
        data:{
            msg:"1.内容是在change事件后才改变的",
            msg2:"2.内容是在change事件后才改变的"
        }
    })
</script>
</body>
</html>

(3)v-for

v-for指令基于源数据重复渲染元素。$index表示索引。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
   <div id="didi-navigator">
       <ul>
           <li v-for="tab in tabs">
               {{tab.text}}
           </li>
       </ul>
       <ul>
           <li v-for="tab of tabs">
               {{tab.text}}
           </li>
       </ul>
   </div>
   <script src="js/vue.js"></script>
   <script>
       new Vue({
           el:"#didi-navigator",
           data:{
               tabs:[
                   {text:"巴士"},
                   {text:"快车"},
                   {text:"顺风车"},
                   {text:"出租车"},
                   {text:"代驾"}
               ]
           }
       });

   </script>
</body>
</html>

v-for="tab in tabs" 代码里tabs是数组名,tab是数组元素。除了in语法,也支持of关键字哦。

v-for指令的源码分析:

源码进入调试,逐行验证

inMatch通过正则匹配,返回一个匹配数组,查看变量结果是

if语句进入,itMatch为null,那么会把索引为1的元素tab作为数组元素的别名。

this.expresssion当然是数组的名字。

接下来是如果别名为空,那么可能会给出出错信息,就是控制台的报错了。

v-for如何应用到组件上呢

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="didi-navigator">
    <one v-for="tab in tabs">
        <p>{{tab.text}}</p>
    </one>
</div>
<script src="js/vue.js"></script>
<script>
    Vue.component("one",{
        template:""
    })
    new Vue({
        el:"#didi-navigator",
        data:{
            tabs:[
                {text:"巴士"},
                {text:"快车"},
                {text:"顺风车"},
                {text:"出租车"},
                {text:"代驾"}
            ]
        }
    });

</script>
</body>
</html>

数组数据变动时如何检测?

首先上DEMO

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <ul>
        <li v-for="tab in tabs">
            {{tab.text}}
        </li>
    </ul>
    <button v-on:click="pushData">向tabs数组添加内容</button>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
            tabs:[
                {text:"巴士"},
                {text:"快车"},
                {text:"顺风车"},
                {text:"出租车"},
                {text:"代驾"}
            ]
        },
        methods:{
            pushData:function(){
                this._data.tabs.push({text:"其他"});
            }
        }
    });

</script>
</body>
</html>

当我们点击按钮,那么“其他”这一项内容被添加到tabs数组里,并且v-for指令有被再次渲染。这也就是现在的问题,数组的数据变动,会触发试图更新。

首先,使用original遍历的第一个push方法存起来。

再次,把参数也就是DEMO里面的{text:"其他"},插入被观察的数组里。

if (inserted) ob.observeArray(inserted);

最后,在返回结果数组前触发更新。

ob.dep.notify();

所以,vue.js重写了这些方法,触发了一次notify。

第二个是vue.js还增加了$set和$remove方法来观测变化。

源代码:

def(arrayProto, ‘$set‘, function $set(index, val) {
    if (index >= this.length) {
      this.length = Number(index) + 1;
    }
    return this.splice(index, 1, val)[0];
  });

可以看到$set通过Splice来插入值。

源代码:

def(arrayProto, ‘$remove‘, function $remove(item) {
    /* istanbul ignore if */
    if (!this.length) return;
    var index = indexOf(this, item);
    if (index > -1) {
      return this.splice(index, 1);
    }
  });

$remove也是通过splice来删除的。

尽量避免直接设置数据绑定的数组元素,这些变化不会被vue.js检测到,从而不渲染视图。这时,可使用$set方法。

也可以使用filter、concat、slice方法,返回的数组将是一个不同的实例。

filter的DEMO:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <ul>
        <li v-for="tab in tabs">
            {{tab.text}}
        </li>
    </ul>
    <button v-on:click="filter">添加内容</button>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
            tabs:[
                {text:"巴士"},
                {text:"快车"},
                {text:"顺风车"},
                {text:"出租车"},
                {text:"代驾"}
            ]
        },
        methods:{
            filter:function(){
                this._data.tabs=this._data.tabs.filter(function(item){
                     item.text=item.text+"添加字符串";
                    return item;
                })
            }
        }
    });

</script>
</body>
</html>

concat方法的示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <button v-on:click="concatArr">合并数组</button>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        methods:{
            concatArr:function(){
                var listdata= [{
                    "smallclassid": "21",
                    "smallclassname": "长沙菜"
                }, {
                    "smallclassid": "6",
                    "smallclassname": "湘菜分类"
                }];

                var data = [{
                    smallclassid:0,
                    smallclassname:‘全部‘
                }];

                var newdata = data.concat(listdata);
                console.log(newdata);
            }
        }
    });

</script>
</body>
</html>

track-by让数据替换更加高效。

默认情况下,v-for可能重新渲染整个列表,可能局部渲染,看数据的特征。那么,如果每个对象都有一个唯一的ID属性,那么用track-by特性给vue.js提示,以尽可能的复用已有实例。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <ul>
        <li v-for="tab in tabs" track-by="_uid">
            {{tab.text}}
        </li>
    </ul>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
            tabs:[
                {text:"巴士",_uid:"01"},
                {text:"快车",_uid:"02"},
                {text:"顺风车",_uid:"03"},
                {text:"出租车",_uid:"04"},
                {text:"代驾",_uid:"05"}
            ]
        },
        methods:{
        }
    });

</script>
</body>
</html>

当替换数组tabs时,如果vue.js遇到一个包含_uid的新对象,那么vue.js就可以知道可以复用已有对象的作用域与DOM元素,避免重复工作。当然也可以使用track-by="$index",它强制v-for进入原位更新模式。

但是DOM节点不再映射数组元素顺序的改变,不能同步临时状态(比如input元素的值),以及组件的私有状态。因此v-for包含input元素或者子组件时,则要小心使用track-by="$index"。

vue.js不能检测到变化。

直接用索引设置元素,比如,vm.items[0]={}。

修改数据的长度,vm.items.length=0.

v-for遍历一个对象,每个重复的实例都有一个特殊的属性$key。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <ul>
       <li v-for="item in items">{{$key}}:{{item.msg}}</li>
    </ul>
    <ul>
       <li v-for="(key,item) in items">{{key}}:{{item.msg}}</li>
    </ul>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
            items:{
                one:{
                    msg:"Hello"
                },
                two:{
                    msg:"DIDI FE"
                }
            }
        }
    });

</script>
</body>
</html>

v-for也支持整数。

<div v-for="n in 10">Hi!{{$index}}</div>

filterBy的使用

语法:filterBy searchKey [in dataKey...]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <input v-model="searchText" type="text"/>
    <ul>
        <li v-for="user in users | filterBy searchText in ‘name‘">{{user.name}}</li>
        <!--在users的name字段中过滤出我们想要的信息,并展示出来。-->
    </ul>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
             users:[
                 {
                     name:"开车",
                     tag:"1"
                 },
                  {
                     name:"出租车",
                     tag:"2"
                 },
                  {
                     name:"顺风车",
                     tag:"3"
                 },
                  {
                     name:"专车",
                     tag:"4"
                 },

             ]
        }
    });

</script>
</body>
</html>

效果看起来很棒,像使用搜索引擎的感觉,当输入某个关键字后就会下拉展示相关搜索词。

orderBy的使用

语法:orderBy sortKey[reverseKey]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <ul>
        <li v-for="user in users | orderBy field  reverse">{{user.name}}</li>
        <!--在ul标签中根据field代表的tag字段正序排列数据。-->
    </ul>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
            field:"tag",
            reverse:false,
            users:[
                {
                    name:"快车",
                    tag:"1"
                },
                {
                    name:"出租车",
                    tag:"3"
                },
                {
                    name:"顺风车",
                    tag:"2"
                },
                {
                    name:"专车",
                    tag:"0"
                },

            ]
        }
    });

</script>
</body>
</html>

(4)v-text、v-html和v-bind

v-text指令类似于文本插值,会构建一个文本节点的。v-html插入html片段。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <h5>1.v-text指令</h5>
    <span v-text="msg"></span>
    <h5>2.v-html</h5>
    <span v-html="html"></span>

</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
           msg:"v-text内容",
            html:"<span>html内容</span>"
        }
    });

</script>
</body>
</html>

v-bind可以绑定一个或者多个attribute属性。

v-bind动态绑定src属性:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <img v-bind:src="imgSrc" width="121px" height="75px"/>
    <h5>简写为:</h5>
    <img :src="imgSrc"/>

</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
            imgSrc:"images/1.jpg"
        }
    });

</script>
</body>
</html>

v-bind绑定class或者style时,支持变量,还支持数组或者对象哦。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .yellow{
            color:yellow;
        }
        .size{
            font-size:20px;
        }
    </style>
</head>
<body>
<div id="didi-navigator">
   <p :class="[classA,classB]">我是段落</p>
   <div v-bind="{id:div1}">我是div的内容</div>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
            classA:"yellow",
            classB:"size",
            div1:"div1"
        }
    });

</script>
</body>
</html>

v-bind没有参数时,直接绑定到一个对象。

组件绑定,使用 v-bind:prop 绑定。到组件一章再说咯。

(5)v-on指令

v-on指令用于绑定事件监听器。普通元素,只能监听原生的DOM事件,并可使用变量$event访问原生DOM事件。使用在自定义元素的组件上,也可以监听子组件触发的自定义事件。

和v-bind:src缩写为:src一样,v-on:click也可以简写,@click。除了事件参数外,还可以增加修饰符。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <!--方法处理器-->
    <button v-on:click="doThis">do this</button>
    <!--内联语句-->
    <button v-on:click="doThat(‘hello‘,$event‘)">do that</button>
    <!--缩写-->
    <button @click="doThis">缩写</button>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
            tabs:[
                {text:"巴士"},
                {text:"快车"},
                {text:"顺风车"},
                {text:"出租车"},
                {text:"代驾"}
            ]
        },
        methods:{
        }
    });

</script>
</body>
</html>

.stop—调用event.stopPropagation(),阻止冒泡

.prevent—调用event.preventDefault(),阻止默认行为。

.captrue—添加事件侦听器使用capture模式。

.self—只当事件是从侦听器绑定的元素本身触发时才触发回调。

.{keyCode|keyAlias}—只在指定按键上触发回调。

vue.js提供的键值有:esc是27,tab是9,enter是13,delete是8和46,up是38,left是37,right是39,down是40。

enter键盘事件DEMO:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <input @keyup.13="onEnter" type="text"/>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
            tabs:[
                {text:"巴士"},
                {text:"快车"},
                {text:"顺风车"},
                {text:"出租车"},
                {text:"代驾"}
            ]
        },
        methods:{
            onEnter:function(){
                alert("enter键");
            }
        }
    });

</script>
</body>
</html>

(6)v-ref、v-el、v-pre和v-cloak指令

v-ref是在父组件上注册一个子组件的索引,便于直接访问,必须提供参数id,也可以通过父组件的$ref对象访问子组件。(涉及到组件,略讲。)

v-el为DOM元素注册一个索引,方便通过所属实例的$els访问这个元素,

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <span v-el:msg>hello</span>
    <button @click="getHello">获取hello的值</button>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        el:"#didi-navigator",
        data:{
        },
        methods:{
            getHello:function(){
                var content=this.$els.msg.textContent;
                alert(content);
            }
        }
    });

</script>
</body>
</html>

v-pre编译时跳过当前元素和它的子元素。

v-cloak指令保持在元素上直到关联实例结束编译,类似于angularJS的ng-cloak。它用来未被编译的mustache标签直到实例准备完毕。它相当于增加了一个v-locak类。

[v-cloak]{

   display:none;

}

3.自定义指令

vue.js提供了两种方式,一种是Vue.directive注册全局指令,另一种是组件的directives注册一个局部指令。

(1)钩子函数:bind是准备工作,update是值更新时的工作,unbind是清理工作。当只需要update函数时,可以传入一个函数替代定义对象。

(2)钩子函数的this对象。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
     <div v-hello="msg"></div>
</div>
<script src="js/vue.js"></script>
<script>
    Vue.directive("hello",{
       bind:function(){
           console.log(this);
       },
        update:function(value){
           console.log(value);
        }
    });
    var vm=new Vue({
        el:"#didi-navigator",
        data:{
            msg:"hello,everyone"
        }
    });

</script>
</body>
</html>

打印的this对象如截图

所有的钩子函数都将被复制到实际的指令对象中,在钩子内this指向这个指令对象。this对象的各个属性含义:

el-指令绑定的元素。

vm-拥有该指令的上下文ViewModel。

expression-指令的表达式,不包括参数和过滤器。

arg-指令的参数。

name-指令的名字,不包含前缀。

modifiers-一个对象,包含指令的修饰符。

descriptor-一个对象,包含指令的解析结果。

注意:我们应当将这些属性视为只读,不要修改它们。也可以给指令对象添加自定义属性,但不要覆盖原有的内部属性。

(3)指令支持传入一个JS对象字面量

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <div v-hello="{color:‘white‘,text:‘hello,,everyone!‘}"></div>
</div>
<script src="js/vue.js"></script>
<script>
    Vue.directive("hello",{

        update:function(value){
            console.log(value.color);
            console.log(value.text);
        }

    });
    var vm=new Vue({
        el:"#didi-navigator",
        data:{
        }
    });

</script>
</body>
</html>

同时当只需要一个update函数时,那么可以简写为

Vue.directive("hello",function(value){
    console.log(value.color);
    console.log(value.text);
);

(4)当使用了字面修饰符时,它的值将按照普通字符串处理,update只调用一次,那么普通字符串不能响应数据变化。

(5)元素指令

元素指令的意思是指令当做一个元素来使用,元素指令可以看做一个轻量组件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <hello class="demo" name="hi"></hello>
</div>
<script src="js/vue.js"></script>
<script>
    Vue.elementDirective("hello",{
        bind:function(){
            console.info(this.el.className);
            console.info(this.el.getAttribute("name"));
        }
    });
    var vm=new Vue({
        el:"#didi-navigator",
        data:{

        }
    });

</script>
</body>
</html>

(6)高级选项:params

自定义指令接受一个params数组,指定一个特性列表。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <hello class="demo" name="hi" a="ddd" b="cccc">hello内容</hello>
</div>
<script src="js/vue.js"></script>
<script>
    Vue.elementDirective("hello",{
        params:["a","b"],
        bind:function(){
            console.log(this.params)
        }
    });
    var vm=new Vue({
        el:"#didi-navigator",
        data:{

        }
    });

</script>
</body>
</html>

params也支持动态属性,this.params[key]会自动保持更新,使用paramWathers对象来定义的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    {{someValue}}
    <my-directive class="hello" name="hi" v-bind:a="someValue"></my-directive>
    <input type="text" v-model="someValue"/>
</div>
<script src="js/vue.js"></script>
<script>
    Vue.elementDirective("my-directive",{
        params:["a"],
        paramWatchers:{
            a:function(val,oldVal){
                console.log("a changed");
            }
        }
        //param监听a变量。如果a发生变化,那么就会执行响应的代码咯
    });
    var vm=new Vue({
        el:"#didi-navigator",
        data:{
            someValue:"value"
        }
    });

</script>
</body>
</html>

(7)高级选项:deep

当自定义指令使用在一个对象上,当对象内部属性变化时要出发update(响应变化),那么需要在指令对象上指定deep:true。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    {{someValue}}
    <div v-demo="a"></div>
    <span>{{a.b}}</span>
    <button @click="change">change</button>
</div>
<script src="js/vue.js"></script>
<script>
    Vue.directive("demo",{
        deep:true,
        update:function(obj){
            console.log(obj.b)
        }
    });
    var vm=new Vue({
        el:"#didi-navigator",
        data:{
            a:{
                b:2
            }
        },
        methods:{
            change:function(){
                vm.a.b=4;
            }
        }
    });

</script>
</body>
</html>

(8)高级选项:twoWay

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    自定义组件:<input v-example="a.b.c"/>
    父作用域:{{a.b.c}}
</div>
<script src="js/vue.js"></script>
<script>
    Vue.directive(‘example‘, {
        twoWay: true,
        bind: function () {
            this.handler = function () {
                // 将数据写回 vm
                // 如果指令这样绑定 v-example="a.b.c"
                // 它将用给定值设置 `vm.a.b.c`
                this.set(this.el.value)
            }.bind(this)
            this.el.addEventListener(‘input‘, this.handler)
        },
        unbind: function () {
            this.el.removeEventListener(‘input‘, this.handler)
        }
    });
    var vm=new Vue({
        el:"#didi-navigator",
        data:{
            a:{
                b:{
                    c:2
                }
            }
        }
    });
</script>
</body>
</html>

(9)高级选项:acceptStatement

允许接收内联语句。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div id="didi-navigator">
    <div v-demo="a++"></div>
    {{a}}
</div>
<script src="js/vue.js"></script>
<script>
    Vue.directive("demo",{
        acceptStatement:true,
        update:function(fn){
            console.log(fn.toString());
            fn();         //传入值是一个函数,调用它,就是调用"a++"语句。
        }
    });
    var vm=new Vue({
        el:"#didi-navigator",
        data:{
            a:5
        }
    });

</script>
</body>
</html>

(10)高级选项:terminal

遇到terminal指令会停止遍历这个元素的后代元素,然后由这个指令接管编译这元素及其后代元素的任务。v-if和v-for都是terminal指令。

(11)高级选项:priority

给指令指定一个优先级。没有,默认是1000,terminal指令默认是2000.优先级高的指令处理的早,一样的按顺序处理,但却不能保证在所有浏览器都一直。

另外,流程控制指令v-if和v-for在编译过程中始终有最高的优先级。

4.源码实现

内部指令是如何实现的?

v-model指令的实现源码

var model = {

    priority: MODEL,
    twoWay: true,
    handlers: handlers,
    params: [‘lazy‘, ‘number‘, ‘debounce‘],

    /**
     * Possible elements:
     *   <select>
     *   <textarea>
     *   <input type="*">
     *     - text
     *     - checkbox
     *     - radio
     *     - number
     */

    bind: function bind() {
      // friendly warning...
      this.checkFilters();
      if (this.hasRead && !this.hasWrite) {
        ‘development‘ !== ‘production‘ && warn(‘It seems you are using a read-only filter with ‘ + ‘v-model="‘ + this.descriptor.raw + ‘". ‘ + ‘You might want to use a two-way filter to ensure correct behavior.‘, this.vm);
      }
      var el = this.el;
      var tag = el.tagName;
      var handler;
      if (tag === ‘INPUT‘) {
        handler = handlers[el.type] || handlers.text;
      } else if (tag === ‘SELECT‘) {
        handler = handlers.select;
      } else if (tag === ‘TEXTAREA‘) {
        handler = handlers.text;
      } else {
        ‘development‘ !== ‘production‘ && warn(‘v-model does not support element type: ‘ + tag, this.vm);
        return;
      }
      el.__v_model = this;
      handler.bind.call(this);
      this.update = handler.update;
      this._unbind = handler.unbind;
    },

    /**
     * Check read/write filter stats.
     */

    checkFilters: function checkFilters() {
      var filters = this.filters;
      if (!filters) return;
      var i = filters.length;
      while (i--) {
        var filter = resolveAsset(this.vm.$options, ‘filters‘, filters[i].name);
        if (typeof filter === ‘function‘ || filter.read) {
          this.hasRead = true;
        }
        if (filter.write) {
          this.hasWrite = true;
        }
      }
    },

    unbind: function unbind() {
      this.el.__v_model = null;
      this._unbind && this._unbind();
    }
  };

表单元素radio的实现

var radio = {

    bind: function bind() {
      var self = this;
      var el = this.el;

      this.getValue = function () {
        // value overwrite via v-bind:value
        if (el.hasOwnProperty(‘_value‘)) {
          return el._value;
        }
        var val = el.value;
        if (self.params.number) {
          val = toNumber(val);
        }
        return val;
      };

      this.listener = function () {
        self.set(self.getValue());
      };
      this.on(‘change‘, this.listener);

      if (el.hasAttribute(‘checked‘)) {
        this.afterBind = this.listener;
      }
    },

    update: function update(value) {
      this.el.checked = looseEqual(value, this.getValue());
    }
  };

第四章:计算属性

为了避免过多的逻辑造成模板的臃肿不堪,可使用计算属性来简化逻辑。

1.什么是计算属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   <div id="example">
       <input type="text" v-model="didi"/>
       <input type="text" v-model="family"/>
       <br/>
       didi={{didi}},family={{family}},didiFamily={{didiFamily}}
   </div>
    <script src="js/vue.js"></script>
   <script>
       var vm=new Vue({
           el:"#example",
           data:{
               didi:"didi",
               family:"family"
           },
           computed:{
               //一个计算属性的getter
               didiFamily:{
                   get:function(){
                       //this 指向vm实例
                       return this.didi+this.family;
                   }
               }
           }
       })
   </script>
</body>
</html>

当vm.didi和vm.family的值发生变化时,vm.didiFamily的值会自动更新,当然也会同步到DOM元素上。

2.计算属性的性能分析

第五章:表单控件绑定

1.v-model更新表单控件的基本例子

这些基本例子,直接使用value属性,绑定的都是字符串或者checkbox的布尔值。接下来分别介绍。

(1)文本框的使用

当用户操作文本框时,vm.name会自动更新为用户输入的值,同时span也会改变。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="demo">
        <span>Welcom,{{name}}!join DDFE</span>
        <br/>
        <input type="text" v-model="name" placeholder="join DDFE"/>
    </div>
    <script src="js/vue.js"></script>
    <script>
        var vm=new Vue({
            el:"#demo"
        })
    </script>
</body>
</html>

textInput使用v-model

(2)复选框checkbox的使用

单个复选框的使用和文本框类似,多个复选框,也就是复选框组,被选入的值会放入一个数组。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>复选框组</title>
</head>
<body>
<div id="demo">
    <input type="checkbox" id="flash" value="flash" v-model="bizLines"/>
    <label for="flash">
        快车
    </label>
    <br/>
    <input type="checkbox" id="premium" value="premium" v-model="bizLines"/>
    <label for="premium">
        专车
    </label>
    <br/><input type="checkbox" id="bus" value="bus" v-model="bizLines"/>
    <label for="flash">
        巴士
    </label>
    <br/>
</div>
<script src="js/vue.js"></script>
<script>
    var vm=new Vue({
        el:"#demo",
        data:{
            bizLines:[]
        }
    })
</script>
</body>
</html>

复选框组通过v-model被选中的值会放入数组中

(3)单选按钮radio的使用

当单选按钮被选中时,v-model的变量值会被赋值为对应的value值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>单选按钮radio</title>
</head>
<body>
<div id="demo">
    <input type="radio" id="flash" value="flash" v-model="bizLines"/>
    <label for="flash">
        快车
    </label>
    <br/>
    <input type="radio" id="premium" value="premium" v-model="bizLines"/>
    <label for="premium">
        专车
    </label>
    <br/>
    <input type="radio" id="bus" value="bus" v-model="bizLines"/>
    <label for="flash">
        巴士
    </label>
    <br/>
    <span>Picked:{{bizLines}}</span>
</div>
<script src="js/vue.js"></script>
<script>
    var vm=new Vue({
        el:"#demo"
    })
</script>
</body>
</html>

单选按钮使用v-model

(4)select控件使用v-model分为两种情况。

一种是单选select控件,第二种是多选select控件。v-model指令都用于select标签。动态的生成option可以借助v-for指令等。

单选时vm.selected为对应的option的value值。多选会被放入一个数组中,多选是selectr有multiple属性,浏览器窗口想要多选可以借助ctrl和shift快捷键。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>下拉菜单的选择</title>
</head>
<body>
<div id="demo">
    <select v-model="bizLine">
        <option selected value="flash">快车</option>
        <option value="premium">专车</option>
        <option value="bus">巴士</option>
    </select>
    <span>selected:{{bizLine}}</span>
    <br/>
    <select v-model="bizLine2" multiple>
        <option selected value="flash">快车</option>
        <option value="premium">专车</option>
        <option value="bus">巴士</option>
    </select>
    <span>selected:{{bizLine2|json}}</span>
</div>
<script src="js/vue.js"></script>
<script>
    var vm=new Vue({
        el:"#demo"
    })
</script>
</body>
</html>

2.动态的值绑定

通过v-bind代替直接使用value属性,那么除了字符串,还可以是数值、对象、数组等非字符串的值。

(1)checkbox

3.v-model指令的修饰词及其源码分析

(1)lazy

默认情况下,v-model在input事件中同步输入框的值与数据,而添加了lazy特性后,在change事件中去掉同步性。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="demo">
    <span>Welcom,{{name}}!join DDFE</span>
    <br/>
    <input type="text" v-model="name" placeholder="join DDFE" />
</div>
<script src="js/vue.js"></script>
<script>
    var vm=new Vue({
        el:"#demo"
    })
</script>
</body>
</html>
</body>
</html>

lazy修饰词

同样是之前的代码,只是添加了lazy属性,那么name变量就不会同步了。

<!--源码目录:src/directives/public/model/text.js-->

var lazy = this.params.lazy  //获取到参数的lazy的布尔值
//...
if (!isRange && !lazy) {     //如果element的type值不是range,而且lazy为false
      this.on(‘focus‘, function () {
        self.focused = true
      })
      this.on(‘blur‘, function () {
        self.focused = false
        // do not sync value after fragment removal (#2017)
        if (!self._frag || self._frag.inserted) {
          self.rawListener()
        }
      })
    }
//...
if (this.hasjQuery) {
      const method = jQuery.fn.on ? ‘on‘ : ‘bind‘
      jQuery(el)[method](‘change‘, this.rawListener)
      if (!lazy) {
        jQuery(el)[method](‘input‘, this.listener)
      }
    } else {
      this.on(‘change‘, this.rawListener)
      if (!lazy) {
        this.on(‘input‘, this.listener)
      }
    }

(2)debounce

<!--源码目录:src/directives/public/model/text.js-->

if (debounce) {
      this.listener = _debounce(this.listener, debounce)
    }

    // Support jQuery events, since jQuery.trigger() doesn‘t
    // trigger native events in some cases and some plugins
    // rely on $.trigger()
    //
    // We want to make sure if a listener is attached using
    // jQuery, it is also removed with jQuery, that‘s why
    // we do the check for each directive instance and
    // store that check result on itself. This also allows
    // easier test coverage control by unsetting the global
    // jQuery variable in tests.
    this.hasjQuery = typeof jQuery === ‘function‘
    if (this.hasjQuery) {
      const method = jQuery.fn.on ? ‘on‘ : ‘bind‘
      jQuery(el)[method](‘change‘, this.rawListener)
      if (!lazy) {
        jQuery(el)[method](‘input‘, this.listener)
      }
    } else {
      this.on(‘change‘, this.rawListener)
      if (!lazy) {
        this.on(‘input‘, this.listener)
      }
    }

(3)number

<!--源码目录:src/directives/public/model/text.js-->

var number = this.params.number
//****
this.listener = this.rawListener = function () {
      if (composing || !self._bound) {
        return
      }
      var val = number || isRange
        ? toNumber(el.value)
        : el.value
      self.set(val)
      // force update on next tick to avoid lock & same value
      // also only update when user is not typing
      nextTick(function () {
        if (self._bound && !self.focused) {
          self.update(self._watcher.value)
        }
      })
    }
//****

<!--源码目录:src/util/lang.js-->

export function toNumber (value) {
  if (typeof value !== ‘string‘) {
    return value
  } else {
    var parsed = Number(value)
    return isNaN(parsed)
      ? value
      : parsed
  }
}
时间: 2024-08-05 11:08:11

vue.js基础知识篇(1):简介、数据绑定、指令、计算属性、表单控件绑定和过滤器的相关文章

vue.js基础知识篇(3):计算属性、表单控件绑定

第四章:计算属性 为了避免过多的逻辑造成模板的臃肿不堪,可使用计算属性来简化逻辑. 1.什么是计算属性 <!DOCTYPE html> <html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <div id="example"> <

分针网—每日分享:Vue.js事件处理器与表单控件绑定

事件处理主要通过v-on这个指令来执行. 事件监听及方法处理 1.简单的可以直接内嵌在页面. 2.可以通过将方法定义在methods中,然后再v-on中执行 3.可以通过绑定给函数传递参数,还可以传递通过变量$event给函数传递原生DOM事件. <div id="app-1"> <button v-on:click="counter += 1">增加1</button> <p>这个按钮被点击了{{counter}}&

Vue 表单控件绑定

表单控件绑定 基础用法 可以用 v-model 指令在表单控件元素上创建双向数据绑定.根据控件类型它自动选取正确的方法更新元素.尽管有点神奇,v-model 不过是语法糖,在用户输入事件中更新数据,以及特别处理一些极端例子. Text <span>Message is: {{ message }}</span> <br> <input type="text" v-model="message" placeholder=&qu

vue表单控件绑定+自定义组件

vue表单控件绑定 v-model 在表单控件元素上创建双向数据绑定 文本框双向绑定 多选框演示 下拉列表演示 vue自定义组件 组件放在components目录下 组件基本要素:props  $emit 通过import导入自定义组件 制作一个倒计时组件: 1.在conponents目录下,新建一个time.vue 方法写在mouted声明周期函数内,代码如下: 然后在index.vue中使用组件: 我之前组件命名为time,可能与默认什么冲突了,然后报错不让用,所以改名成cyytime 但是

vue.js基础知识篇(2):指令详解

第三章:指令 1.语法 指令以v-打头,它的值限定为绑定表达式,它负责的是按照表达式的值应用某些行为到DOM上. 内部指令有v-show,v-else,v-model,v-repeat,v-for,v-text,v-el,v-html,v-on,v-bind,v-ref,v-pre,v-cloak,v-if. 2.内部指令 (1)控制元素的显示与否:v-if,v-show.v-else v-if是真实的条件渲染,根据表达式的true/false在DOM中生成或移除一个元素. 第一,这个指令是惰性

Vue.js学习笔记 第七篇 表单控件绑定

本篇主要说明表单控件的数据绑定,这次没有新的知识点 文本框 1.普通文本框 <div id="app-1"> <p><input v-model="textBox" placeholder="输入内容...">输入的内容:{{ textBox }}</p> </div> <script type="text/javascript"> var vm1 = n

2017.04 vue学习笔记---08表单控件绑定---基础用法

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> div{ margin-bottom: 30px; } </style> <script src="js/vue.js"></script> <

Vue.js-----轻量高效的MVVM框架(七、表单控件绑定)

话不多说,先上完整代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script type="text/javascript" src="js/vue.js"></script> <title></title> </head> <body> <h2>表

vue.js基础知识篇(6):组件详解

第11章:组件详解 组件是Vue.js最推崇也最强大的功能之一,核心目标是可重用性. 我们把组件代码按照template.style.script的拆分方式,放置到对应的.vue文件中. 1.注册 Vue.js的组件注册分为全局注册和局部注册. 全局注册使用Vue.component方法.第一个参数是组件名字,第二个参数是组件的构造函数,要么是function,要么是object. <!DOCTYPE html> <html lang="en"> <hea