Vue入门

Vue.js 是一个用于构建用户界面的渐进式框架,本文档主要介绍Vue实例的构造器、属性、方法和生命周期,包括如何创建、扩展实例以及实例的生命周期。接着讲解了Vue的模板语法,如插值、指令、过滤器、缩写,以及计算属性和观察者的基本用法。此外,还涵盖了Class与Style的绑定,条件渲染、列表渲染和事件处理。最后,探讨了组件的使用,包括Prop的传递、自定义事件以及内容分发。
摘要由CSDN通过智能技术生成

Vue实例

构造器

每个Vue.js应用都是通过构造函数vue创建一个Vue的根实例启动的:

var vm = new Vue({
  //选项
});

Vue.js没有完全遵循MVVM模式,Vue的设计无疑是收到了它的启发。因为在文档中经常会使用vm(viewModel的简称)这个变量名表示Vue实例

在实例化Vue时,需要传入一个选项对象,它可以包含数据、模板、挂载元素、方法、生命周期钩子等选项

可以扩展 vue构造器,从而用预定义选项创建可复用的组件构造器:

var myComponent = Vue.extend({
  //扩展选项
});
//所有的MyComponent实例都将以预定义的扩展选项被创建
var myComponent = new myComponent();

尽管可以命令的创建扩展实例,不过在大多数情况下将组件构造器注册为一个自定义元素,然后声明式地用在模板中

属性和方法

每个Vue实例都会代理其data对象里面所有的属性:

var data = {a : 1};
var vm = new Vue({data : data});
vm.a === data.a;   //true

vm.a = 2;
data.a //2

data.a = 3;
vm.a //3

只有这些被代理的属性是响应的,如果在实例创建之后添加新的属性到实例上,它不会触发视图更新

除了data属性,Vue实例暴露了一些有用的实例属性和方法,这些属性和方法都有前缀$,以便与代理的data属性区分,例如

var data = {a : 1};
var vm = new Vue({
  el : "#example",
  data : data
});

vm.$data === data;   //true
vm.$el === document.getElementById('example');  //true

//$watch是一个实例方法
vm.$watch('a', function() {
   
  //这个回掉将在"vm.a"改变后调用
});

注意:不要在实例属性或者回掉函数中(如vm.$watch(‘a’, newVal=>this.method()))使用箭头函数。因为箭头函数绑定父上下文,所以this不会像是预想的一样是Vue实例,而是this.myMethod未被定义

实例生命周期:

每个Vue实例在被创建之前都要经过一系列的初始化过程,例如需要配置数据观测、模板编译、挂载实例到DOM,然后在数据变化时更新DOM。在这个过程中,实例也会调用一些生命周期钩子,这就给我们提供了执行自定义逻辑的机会,例如,created这个钩子在实例被创建之后调用

var vm = new Vue({
  data: {
    a : 1
  },
  //this指向Vue实例
  created: function() {
   
    console.log('a is: ' + this.a);   //'a is: 1'
  }
});

也有其他的一些钩子,比如mountedupdatedestoryed,钩子的this指向的调用它的Vue的实例。钩子的this指向调用它的Vue的实例,Vue.js中是没有控制器的概念的,组件的自由逻辑可以分布在这些钩子中

生命周期图示

模板语法

Vue.js使用了基于HTML的模板语法,允许开发者声明式地将DOM绑定至底层Vue实例的数据,所有Vue的模板都是合法的HTML,所以能被遵循规范的浏览器和HTML解析器解析

在底层的实现上,Vue将模板编译成虚拟DOM渲染函数。结合响应系统,在应用状态改变时,Vue能够智能的计算出重新渲染组件的最小代价并应用到DOM操作上

如果你熟悉虚拟DOM并且偏爱JavaScript的原始力量,也可以不用模板,直接写渲染函数,使用可选的JSX语法

插值

#文本

数据绑定最常见的形式就是使用“Mustache”语法(双大括号)的文本插值

<span>message: {
  {msg}}</span>

Mustache 标签将会被替代为对应数据上的msg的属性的值,无论何时,绑定的数据对象上msg属性发生了变化,插值处的内容都会更新

通过使用v-once指令,你也能一次性地插值,当数据改变时,插值处的内容不会更新,但请留心这会影响该结点上的所有的数据绑定

<span v-once>This will never change: {
  {msg}}</span>

#纯HTML

双大括号会将数据解释为纯文本,而非HTML。为了输出真正的HTML,需要使用v-html指令

<div v-html="rawHtml"></div>

被插入的内容都会被当成HTML——数据绑定会被忽略,注意,不能使用v-html来复合局部模板,因为Vue不是基于字符串的模板引擎。组件更适合担任UI重用与复合的基本单元

在站点上使用动态渲染的任意HTML可能会非常危险,因为会很容易造成XSS攻击,所以只对可信内容进行使用HMTL插值,绝不要对用户提供的内容插值

#属性

Mustache不能再HTML属性中使用,应使用v-bind指令

<div v-bind:id="dynamicId"></div>

这对布尔值的属性也有效——如果条件被求值为false的话该属性会被移除:

<button v-bind:disabled="someDynamicCondition"></button>

#使用JavaScript表达式

在之前的例子中,都只是只绑定简单的属性键值,但实际上,对于所有的数据绑定,Vue.js都提供了完全的JavaScript表达式支持

{ {number + 1}}

{ {ok ? ‘Yes’ : ‘No’}}

{ {message.split(”).reverse().join(”)}}

这些表达式会在所属Vue实例的数据作用域下作为JavaScript解析,有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效

    <!--这是一条语句,不是表达式-->
    {
  {var a = 1}}

    <!--流控制也不会生效,但可以使用三元表达式-->
    {
  {if(ok) {
    return message
    }}}

模板表达式都被放到沙盒中,只能访问全局变量的一个白名单,如Math和Data,不应该在模板表达式中试图访问用户定义的全局变量

指令

指令指的是带有v-前缀的特殊属性,指令属性的预期值是单一 JavaScript表达式(除了v-for,之后再讨论)。指令的职责就是当表达式的值改变时相应地将某些行为应用到DOM上

  <p v-if="seen">Now you see me</p>

这里,v-if指令会根据表达式seen的值的真假来移除/插入p元素

#参数

一些指令能接受一个“参数”,在指令后以冒号指明,例如v-bind指令被用来响应的更新HTML属性

<a v-bind:href="href"></a>

这里的href是参数,告知v-bind指令将该元素的href属性与表达式url的值绑定

另一个例子就是v-on指令,它用于监听DOM事件:

<a v-on:click="doSomething"></a>

在这里参数是监听的事件名

#修饰符

修饰符是以半角句号.指明的特殊后缀,用于指出一个指令应该以特殊方式绑定,例如.prevent修饰符告诉v-on指令对于触发的事件的调用event.preventDefault():

  <form v-on:submit.prevent="onSubmit"></form>

过滤器

Vue.js允许你自定义过滤器,可被用作一些常见的文本格式化,过滤器可用与两个地方:插值和v-bind表达式,过滤器应该被添加在JavaScript表达式的尾部,由“管道”符指示

{
  {message | capitalize}}
<div v-bind:id="rawId | formatId"></div>

过滤器函数总接受表达式的值作为第一个参数

new Vue({
  // ...
  filters: {
    capitalize: function (value) {
   
      if (!value) return ''
      value = value.toString()
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
  }
})

过滤器可以关联:

{
   {
   message | filterA | filterB}}

过滤器是JavaScript函数,因此可以接受参数

{
   {
   message | filterA('arg1', 'arg2')}}

这里,字符串的arg1将传给过滤器作为第二个参数,arg2表达式的值将被求值然后传给过滤器作为第三个参数

缩写

v-前缀在模板中使用一个表示Vue特殊属性的明显标识,当使用Vue.js为现有的标记添加动态行为时,它会很有用,但对于一些经常使用的指令来说有点繁琐,同时,当搭建Vue.js管理的是所有模板的SPA时,v-前缀也变得没那么重要了。因为,Vue.js为两个最为常用的治疗另提供了特别的缩写

#v-bind的缩写

<!-- 完整语法 -->
<a v-bind:href="url"></a>
<!-- 缩写 -->
<a :href="url"></a>

#v-on

<!-- 完整语法 -->
<a v-on:click="doSomething"></a>
<!-- 缩写 -->
<a @click="doSomething"></a>

:@ 对于属性名来说都是合法字符,在所有支持 Vue.js 的浏览器都能被正确地解析。而且,它们不会出现在最终渲染的标记。

计算属性

模板内的表达式是非常便利的,但是它们实际上只用于简单的计算,在模板中放入太多的逻辑会让模板过重且难以维护

    <div id="example">
        {
  { message.split('').reverse().join('') }}
    </div>

在这种情况下,模板不再简单和清晰,在意识到这是反向显示message之前,你不得不确认第二遍,当你想要在模板中多次反向显示message的时候,问题会变得更糟糕

这就是对于任何复杂逻辑,都应当使用计算属性的原因

#基础例子

    <div id="example">
        <p>Original message: "{
  {message}}"</p>
        <p>Computed reversed message: "{
  {reversedMessage}}"</p>
    </div>
    <script type="text/javascript">
        new Vue({
           el : "#example",
            data: {
                message: "Vue"
            },
            computed : {
                reversedMessage : function() {
    
                    return this.message.split('').reverse().join('');
                }
            }
        });
    </script>

结果:

Original message: “Vue”

Computed reversed message: “euV”

这里声明了一个计算属性reversedMessage,提供的函数将用作属性vm.reversedMessage的getter

也可以看出在vm.reversedMessage的值始终取决于vm.message的值,这种依赖是以声明的方式创建的:计算属性的getter是没有副作用的,这使得它易于测试和推理

#计算缓存 vs Methods

上面的效果也可以通过调用表达式中的method

    <p id="test">Reversed message: "{
  { reversedMessage() }}"</p>
    <script type="text/javascript">
        new Vue({
            el : "#test",
            data : {
                message : "an element"
            },
            methods: {
                reversedMessage: function () {
    
                    return this.message.split('').reverse().join('')
                }
            }
        })
    </script>

我们可以将同一个函数定义为一个method而不是一个计算属性,对于最终的结果,两种方式确实是相同的,然而,不同的计算属性是基于它们的依赖进行缓存的,计算属性只有在它的相关依赖发生改变时才会重新求值,这就意味着只要message还没有改变,多次访问reversedMessage会立即返回之前的计算结果,而不是再次执行函数,那么意味着下面的计算属性将不再跟新,因为Data.now()不是响应式依赖

computed : {
  now : function() {
   
    return Date.now();
  }
}

相比较的话,只要发生重新渲染,method调用总会执行该函数

缓存的作用:对于性能开销比较大的计算属性A,我们可能有其他的属性依赖于这个A属性,如果没有缓存,那么就需要多次执行这个A的getter方法,如果不希望有缓存的时候,可以用method代替

#Computed属性 vs Watched属性

Vue确实提供了一种更通用的方式来观察和响应Vue实例上的数据变动: watch属性,当你有一些数据需要随着其他数据变动而变动时,很容易滥用watch–特别是如果之前使用过AngularJS,然而,通常更好的想法是使用computed属性而不是命令式的watch回掉。

    <div id="demo">{
  {fullName}}</div>
    <script type="text/javascript">
        new Vue({
            el : "#demo",
            data: {
                firstName : 'Foo',
                lastName : 'Bar',
                fullName : 'Foo Bar'
            },
            watch : {
                firstName : function(val) {
    
                    this.fullName = val + ' ' + this.lastName;
                },
                lastName : function(val) {
    
                    this.fullName = this.firstName + ' ' + val;
                }
            }
        });
    </script>

上面的代码是命令式的和重复的,下面的是用computed属性实现的

#计算setter

计算属性默认是只有getter,不过可以在需要时也可以提供一个setter

// ...
computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...

当运行vm.fullName = 'John Doe'时,setter就会被调用,vm.firstName和vm.lastName就会相应的更新

观察watchers

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的watcher。通过watch选项,来响应数据的变化,当你想要数据发生响应时,执行异步操作或开销较大的操作,这个比较有用

    <div id="watch-example">
        <p>Ask a yes/no question:
            <input v-model="question">
        </p>
        <p>{
  { answer }}</p>
    </div>
    <script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js"></script>
    <script src="https://unpkg.com/lodash@4.13.1/lodash.min.js"></script>
    <script>
        var watchExampleVM = new Vue({
            el: '#watch-example',
            data: {
                question: '',
                answer: 'I cannot give you an answer until you ask a question!'
            },
            watch: {
                // 如果 question 发生改变,这个函数就会运行
                question: function (newQuestion) {
    
                    this.answer = 'Waiting for you to stop typing...'
                    this.getAnswer()
                }
            },
            methods: {
                // _.debounce 是一个通过 lodash 限制操作频率的函数。
                // 在这个例子中,我们希望限制访问yesno.wtf/api的频率
                // ajax请求直到用户输入完毕才会发出
                // 学习更多关于 _.debounce function (and its cousin
                // _.throttle), 参考: https://lodash.com/docs#debounce
                getAnswer: _.debounce(
                        function () {
    
                            var vm = this
                            if (this.question.indexOf('?') === -1) {
                                vm.answer = 'Questions usually contain a question mark. ;-)'
                                return
                            }
                            vm.answer = 'Thinking...'
                            axios.get('https://yesno.wtf/api')
                                    .then(function (response) {
    
                                        vm.answer = _.capitalize(response.data.answer)
                                    })
                                    .catch(function (error) {
    
                                        vm.answer = 'Error! Could not reach the API. ' + error
                                    })
                        },
                        // 这是我们为用户停止输入等待的毫秒数
                        800
                )
            }
        })
    </script>

Class与Style绑定

数据绑定一个常见需求是操作元素的class列表和它的内联样式,因为它们都是属性,我们可以用v-bind处理它们:只需要计算出表达式最终的字符串,不过,字符串拼接麻烦又出错,因此在v-bind用于classstyle时,Vue.js专门增强了它,表达式的结果类型除了字符串之外,还可以是对象或者数组

绑定HTML Class

# 对象语法

我们可以传给v-bind:class一个对象,以动态的切换class

<div v-bind:class="{ active: isActive }"></div>

上面的语法表示classactive的更新将取决于数据属性isActive是否为真。

我们也可以在对象中传入更多属性用来动态切换多个class,此外,v-bind: class指令可以与普通的class属性共存。如下模板:

    <div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }">
    </div>
    <script type="text/javascript">
        new Vue({
            el : ".static",
            data: {
                isActive : true,
                hasError : false
            }
        })
    </script>

得到的结果:

<div class="static active"></div>

当使用v-bind绑定的class属性会随着“isActive”和“hasError”的值的变化而改变的

上面的写法是在class里面写了一个对象,当然也可以通过返回对象的计算属性来完成

    <div class="static" v-bind:class="classObject">
    </div>
    <script type="text/javascript">
        new Vue({
            el : ".static",
            data: {
                isActive : true,
                error : null
            },
            computed: {
                classObject : function() {
    
                    return {
                        isActive : this.isA
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值