美文网首页
Vue.js入门学习

Vue.js入门学习

作者: 纯情_小火鸡 | 来源:发表于2017-07-12 09:44 被阅读31次

    Vue.js 是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计。Vue 的核心库只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与单文件组件和 Vue 生态系统支持的库结合使用时,Vue 也完全能够为复杂的单页应用程序提供驱动。

    构造器

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

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

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

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

    var MyComponent = Vue.extend({
      // 扩展选项
    })
    // 所有的 `MyComponent` 实例都将以预定义的扩展选项被创建
    var myComponentInstance = 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 (newVal, oldVal) {
      // 这个回调将在 `vm.a`  改变后调用
    })
    

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

    下图说明了实例的生命周期:


    lifecycle.png

    下面我们来看下语法:

    1.模板语法

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

    文本

    数据绑定最常见的形式就是使用 “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>
    这个 div 的内容将会被替换成为属性值rawHtml,直接作为 HTML —— 数据绑定会被忽略。

    属性

    Mustache 不能在 HTML 属性中使用,应使用 v-bind 指令:
    <div v-bind:id="dynamicId"></div>
    这对布尔值的属性也有效 —— 如果条件被求值为 false 的话该属性会被移除:
    <button v-bind:disabled="isButtonDisabled">Button</button>

    使用 JavaScript 表达式

    迄今为止,在我们的模板中,我们一直都只绑定简单的属性键值。但实际上,对于所有的数据绑定, Vue.js 都提供了完全的 JavaScript 表达式支持。

    {{ number + 1 }}
    {{ ok ? 'YES' : 'NO' }}
    {{ message.split('').reverse().join('') }}
    <div v-bind:id="'list-' + id"></div>
    

    2.指令

    指令(Directives)是带有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="url"></a>
    在这里href是参数,告知v-bind指令将该元素的href属性与表达式url的值绑定。
    另一个例子是v-on指令,它用于监听DOM事件:
    <a v-on:click="doSomething">
    在这里参数是监听的事件名。

    修饰符

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

    3.过滤器

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

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

    4.缩写

    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>
    

    计算属性

    计算属性 vs Methods

    <p>Reversed message: "{{ reversedMessage() }}"</p>

    // in component
    methods: {
      reversedMessage: function () {
        return this.message.split('').reverse().join('')
      }
    }
    
    

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

    观察 Watchers

    虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的watcher。这是为什么 Vue 提供一个更通用的方法通过watch选项,来响应数据的变化。当你想要在数据变化响应时,执行异步操作或开销较大的操作,这是很有用的。
    例如:

    <div id="watch-example">
      <p>
        Ask a yes/no question:
        <input v-model="question">
      </p>
      <p>{{ answer }}</p>
    </div>
    
    <!-- Since there is already a rich ecosystem of ajax libraries    -->
    <!-- and collections of general-purpose utility methods, Vue core -->
    <!-- is able to remain small by not reinventing them. This also   -->
    <!-- gives you the freedom to just use what you're familiar with. -->
    <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 () {
            if (this.question.indexOf('?') === -1) {
              this.answer = 'Questions usually contain a question mark. ;-)'
              return
            }
            this.answer = 'Thinking...'
            var vm = this
            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
              })
          },
          // 这是我们为用户停止输入等待的毫秒数
          500
        )
      }
    })
    </script>
    

    Class 与 Style 绑定

    绑定 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>
    

    如下 data:

    data: {
      isActive: true,
      hasError: false
    }
    

    渲染为:

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

    isActive或者hasError变化时,class 列表将相应地更新。例如,如果hasError的值为true, class列表将变为"static active text-danger"
    你也可以直接绑定数据里的一个对象:

    <div v-bind:class="classObject"></div>
    
    data: {
      classObject: {
        active: true,
        'text-danger': false
      }
    }
    

    渲染的结果和上面一样。我们也可以在这里绑定返回对象的计算属性。这是一个常用且强大的模式:

    <div v-bind:class="classObject"></div>
    
    data: {
      isActive: true,
      error: null
    },
    computed: {
      classObject: function () {
        return {
          active: this.isActive && !this.error,
          'text-danger': this.error && this.error.type === 'fatal',
        }
      }
    }
    

    数组语法

    我们可以把一个数组传给 v-bind:class ,以应用一个 class 列表:

    <div v-bind:class="[activeClass, errorClass]">
    
    data: {
      activeClass: 'active',
      errorClass: 'text-danger'
    }
    

    渲染为:

    <div class="active text-danger"></div>
    

    如果你也想根据条件切换列表中的 class ,可以用三元表达式:

    <div v-bind:class="[isActive ? activeClass : '', errorClass]">
    

    不过,当有多个条件 class 时这样写有些繁琐。可以在数组语法中使用对象语法:

    <div v-bind:class="[{ active: isActive }, errorClass]">
    

    绑定内联样式

    对象语法

    v-bind:style的对象语法十分直观——看着非常像 CSS ,其实它是一个 JavaScript 对象。 CSS 属性名可以用驼峰式 (camelCase) 或 (配合引号的) 短横分隔命名 (kebab-case):

    <div v-bind:style="styleObject"></div>
    
    data: {
      styleObject: {
        color: 'red',
        fontSize: '13px'
      }
    }
    

    数组语法

    v-bind:style的数组语法可以将多个样式对象应用到一个元素上:
    <div v-bind:style="[baseStyles, overridingStyles]">

    自动添加前缀

    v-bind:style使用需要特定前缀的 CSS 属性时,如transform,Vue.js 会自动侦测并添加相应的前缀。

    条件渲染

    v-if指令实现条件块:

    <h1 v-if="ok">Yes</h1>
    

    也可以用v-else添加一个 “else” 块:

    <h1 v-if="ok">Yes</h1>
    <h1 v-else>No</h1>
    

    v-else-if

    2.1.0 新增
    v-else-if,顾名思义,充当v-if的“else-if 块”。可以链式地使用多次:

    <div v-if="type === 'A'">
      A
    </div>
    <div v-else-if="type === 'B'">
      B
    </div>
    <div v-else-if="type === 'C'">
      C
    </div>
    <div v-else>
      Not A/B/C
    </div>
    

    类似于v-elsev-else-if必须紧跟在v-if或者v-else-if元素之后。

    v-show

    另一个用于根据条件展示元素的选项是v-show指令。用法大致一样:
    <h1 v-show="ok">Hello!</h1>
    不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show是简单地切换元素的 CSS 属性 display 。

    列表渲染

    v-for

    我们用v-for指令根据一组数组的选项列表进行渲染。v-for指令需要以item in items形式的特殊语法,items是源数据数组并且item是数组元素迭代的别名。

    基本用法
    <ul id="example-1">
      <li v-for="item in items">
        {{ item.message }}
      </li>
    </ul>
    
    var example1 = new Vue({
      el: '#example-1',
      data: {
        items: [
          {message: 'Foo' },
          {message: 'Bar' }
        ]
      }
    })
    
    结果:
    Foo
    Bar
    

    key

    当 Vue.js 用v-for正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似 Vue 1.x 的 track-by="$index" 。
    建议尽可能使用v-for来提供key,除非迭代 DOM 内容足够简单,或者你是故意要依赖于默认行为来获得性能提升。

    事件处理器

    监听事件

    可以用v-on指令监听 DOM 事件来触发一些 JavaScript 代码。
    示例:

    <div id="example-1">
      <button v-on:click="counter += 1">增加 1</button>
      <p>这个按钮被点击了 {{ counter }} 次。</p>
    </div>
    
    var example1 = new Vue({
      el: '#example-1',
      data: {
        counter: 0
      }
    })
    

    方法事件处理器

    许多事件处理的逻辑都很复杂,所以直接把 JavaScript 代码写在v-on指令中是不可行的。因此v-on可以接收一个定义的方法来调用。
    示例:

    <div id="example-2">
      <!-- `greet` 是在下面定义的方法名 -->
      <button v-on:click="greet">Greet</button>
    </div>
    
    var example2 = new Vue({
      el: '#example-2',
      data: {
        name: 'Vue.js'
      },
      // 在 `methods` 对象中定义方法
      methods: {
        greet: function (event) {
          // `this` 在方法里指当前 Vue 实例
          alert('Hello ' + this.name + '!')
          // `event` 是原生 DOM 事件
          if (event) {
            alert(event.target.tagName)
          }
        }
      }
    })
    // 也可以用 JavaScript 直接调用方法
    example2.greet() // -> 'Hello Vue.js!'
    
    <!-- 阻止单击事件冒泡 -->
    <a v-on:click.stop="doThis"></a>
    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>
    <!-- 修饰符可以串联  -->
    <a v-on:click.stop.prevent="doThat"></a>
    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>
    <!-- 添加事件侦听器时使用事件捕获模式 -->
    <div v-on:click.capture="doThis">...</div>
    <!-- 只当事件在该元素本身(比如不是子元素)触发时触发回调 -->
    <div v-on:click.self="doThat">...</div>
    

    你可以用v-model指令在表单控件元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model本质上不过是语法糖,它负责监听用户的输入事件以更新数据,并特别处理一些极端的例子。

    使用组件

    注册

    之前说过,我们可以通过以下方式创建一个 Vue 实例:

    new Vue({
      el: '#some-element',
      // 选项
    })
    

    要注册一个全局组件,你可以使用Vue.component(tagName, options)。例如:

    Vue.component('my-component', {
      // 选项
    })
    

    组件在注册之后,便可以在父实例的模块中以自定义元素<my-component></my-component>的形式使用。要确保在初始化根实例之前注册了组件:

    <div id="example">
      <my-component></my-component>
    </div>
    
    // 注册
    Vue.component('my-component', {
      template: '<div>A custom component!</div>'
    })
    
    // 创建根实例
    new Vue({
      el: '#example'
    })
    
    渲染为:
    <div id="example">
      <div>A custom component!</div>
    </div>
    

    局部注册

    不必在全局注册每个组件。通过使用组件实例选项注册,可以使组件仅在另一个实例/组件的作用域中可用:

    var Child = {
      template: '<div>A custom component!</div>'
    }
    new Vue({
      // ...
      components: {
        // <my-component> 将只在父模板可用
        'my-component': Child
      }
    })
    

    构成组件

    组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的。这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性。
    在 Vue 中,父子组件的关系可以总结为 props down, events up。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。看看它们是怎么工作的。

    props-events.png

    相关文章

      网友评论

          本文标题:Vue.js入门学习

          本文链接:https://www.haomeiwen.com/subject/hogvhxtx.html