Vue入门笔记

Vue的入门知识我分红了如上四个顶层概念。
vue实例、指令、组件、模板。
vue官方文档已经很易懂了,可是我但愿把个人理解以及一些容易疏忽的地方记下来,方便我往后更轻松的使用它。css

vue是什么

vue是一套构建用户界面的渐进式框架。我对渐进式框架的理解是,你能够充分的使用vue的功能,包括简单的功能和复杂的功能,彻底按照vue的模式去构建程序。固然你也能够只使用相似数据响应的单一功能。他不强制要求你按照某个模式去书写,也就是说你能够在原有的代码基础上将少许功能用vue去实现也是可行的。html

最喜欢的vue的两个特色是,响应式数据和组件。响应式数据省去了不少监听数据的代码,能够专一在构建界面上。而组件做为模块化思想下延伸出的一个手段,不只能够很好的进行解耦使组件独立存在便于管理,并且能够很好的配合模块化技术进行模块化开发。ES6已经支持模块化。前端

vue和MVVM

data = Model
模板 + 指令 = View
new Vue() = ViewModelvue

推荐一个言简意赅的MVVM说明博文webpack

模板

五种建立模板的方法:web

  • DOM元素模板(Vue实例用)chrome

  • script标签 + x-templatesegmentfault

  • template属性数组

  • .vue文件中template标签缓存

  • inline-template

DOM模板

直接用DOM元素做为模板的方式。仅限vue实例控制区域使用。下面四个是组件模板建立方式。

说明:受HTML限制,标签名不能用驼峰(html大小写不敏感)必须用aa-bb形式。另外受html标准影响,特殊元素内只容许存在特定元素,如tr内只能是td或th,若是想再相似tr里解析组件,要用is属性声明组件。

script标签 + x-template

将script内的内容做为模板的方式。注意组件必须有一个根元素。好比下面那个无用div。并且模板与组件分离了,不在同一个位置,不便于管理。不推荐。

<script type="text/x-template" id="hello-world-template">
  <div>
    <p>Hello hello hello</p>
    <p>Hello hello hello</p>
  </div>
</script>
Vue.component('hello-world', {
  template: '#hello-world-template'
})

template属性

最常规作法,也是最恶心的作法,在js语法环境写html代码,没有代码提示,没有格式化,恶心程度可想而知。

Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})

.vue文件的template标签

<template>
  <div>This will be pre-compiled</div>
</template>

inline-template

直接在插入组件的位置,声明模板。不过和script模板同样,分离了,不便于管理。不推荐。

<my-component inline-template>
  <div>
    <p>These are compiled as the component's own template.</p>
    <p>Not parent's transclusion content.</p>
  </div>
</my-component>

vue实例

vue实例也就是MVVM中的VM(ViewModel)。负责链接view和model。

既然是VM,那么vue实例主要做用是操做数据和自身。

vue实例提供了几个用来操做数据的选项。

data

做为MVVM中的M(Model),data属性用来存储未经处理的原始数据对象。

特性:

  • 新添加的属性不会被响应

这个特性包括两点。
一点是指属性必须在 data 对象上存在它才是响应的。

var vm = new Vue({
  data:{
  a:1
  }
})
// `vm.a` 是响应的
vm.b = 2
// `vm.b` 是非响应的

一点是指Vue 不容许在已经建立的实例上动态添加新的根级响应式属性。既不能将响应属性添加到嵌套的对象上。

vm.a.b = 2

添加响应式新属性的替代方案(2种)以下:

// 第一种
Vue.set(vm.a, 'b', 2)
this.$set(this.a,'b',2)

// 第二种
vm.a = Object.assign({}, vm.a, { b: 2 })
this.a = Object.assign({}, this.a, { b: 2 })
  • 不能响应的数组操做及对应替代方法

// 不能响应
vm.items[indexOfItem] = newValue
// 替代方法
Vue.set(example1.items, indexOfItem, newValue)

// 不能响应
vm.items.length = newLength
// 替代方法
example1.items.splice(indexOfItem, 1, newValue)

computed

vue称他为计算属性,用来对data数据进行处理。由于是对data进行计算,因此为了便于维护和理解,计算属性不要去修改data数据,仅仅引用便可。

特性:

  • 用return的数据渲染view

  • 数据是响应式的

  • 基于依赖缓存计算结果。计算属性只有在它的相关依赖发生改变时才会从新求值。
    好比两个div都靠计算属性A来渲染,那么渲染第二个div时不会从新执行计算属性A,而是直接返回渲染第一个div时计算的值

  • getter 和 setter。
    默认只有一个getter,做用是依赖data变化来执行getter。能够本身设一个setter,做用是直接给计算属性赋值时会触发setter。

methods

区别于computed的方法,一般用来做为事件的回调函数,或者不但愿使用computed的缓存特性时做为computed的替代品。methods方法一样是数据响应式的。

特性:

  • 用return的数据渲染view

  • 数据是响应式的

  • 计算结果不缓存

问题:
如何在methods函数内引用事件元素自己?

一般直接用this就能够引用事件元素自己。

el.onclick = function(){
  console.log(this)
}

可是在Vue里this指向实例或组件自身,因此在Vue里这样引用事件元素自己。

<li @click="warn('msg', $event)"></li>
warn: function (message, event) {
  // 如今咱们能够访问原生事件对象
  if (event) event.preventDefault()
  alert(message)
  console.log(event.currentTarget) // 绑定事件的元素自己
}

这里须要说明的是,引用的event对象是原生event对象,不是相似jQuery包装过的event对象。并且之所在模板里传入$event是由于,event对象的兼容性问题。在IE和chrome内能够经过window.event引用event对象,也就是不须要event形参,可是火狐不能够,火狐必须有event形参,并且将event对象做为实参传入,固然只有一个event形参时不须要显示的将event做为实参传入。问题在于event形参若是是非第一位参数,就必须将event对象显示的做为实参传入。在原生JS中能够以下实现。显然vue提供了很好的解决方法。

asd.onclick = function(event) {
    var ee = event
  function a (msg, event) {
      console.log(event)
      alert(msg)
  }
  a(window.value,ee)
}

watch

当你想要在数据变化响应时,执行异步操做或开销较大的操做时请使用watch

filter

被用做一些常见的文本格式化。

生命周期

vue实例从建立到销毁的过程。在这个过程当中能够经过配置生命周期钩子来处理一些逻辑。
推荐一个说明生命周期的博文

属性代理

vue实例建立后,为了便于访问数据,vue实例对象会代理一些数据。
vm.a直接访问data数据、vm.$data直接访问整个data对象

指令

用来在view层代表数据的用途

v-if 和 v-show

v-show是条件显示,只是切换display: none/block。
v-if是条件渲染。

特殊属性

is

用来声明该模板是哪一个组件。解决两个问题。

  • 动态切换组件

<component v-bind:is="currentView"></component>
  • 解决HTML元素限制

// bad
<table>
  <my-row>...</my-row>
</table>

//good
<table>
  <tr is="my-row"></tr>
</table>

key

vue有一个最大限度复用原则,能够复用的元素会通过少许修改继续复用。
key属性能够屏蔽复用机制。有key属性的元素,每次都会从新渲染。

说明:
key值相同的元素之间也会复用,可是绑定key的元素被从新渲染时(渲染了非相同key的元素)原来的缓存会被清除,再也不被复用

ref

vue实例对象能够经过变量名访问。可是组件没有变量名,因此没有能够访问的接口。
ref提供了访问组件的接口。

<child-comp ref="child"></child-comp>

访问

vm.$refs.child

组件

vue组件是实施前端组件化的一个手段。一个完整的前端组件应该包括属于某一前端UI模块HTML CSS JS部分。可是显然入门教程里的注册方式有模板和JS,可是少了CSS,有点残次品的感受。因此条件容许我仍是更喜欢.vue文件的方式封装组件。

注册组件

三种祖册方式

  • 全局注册(不说了)

  • 局部注册(不说了)

  • 用.vue文件封装组件,并用做为模块进行require

引用组件

给组件取个名

<child-comp ref="child"></child-comp>

访问组件

var parent = new Vue({ el: '#parent' })
// 访问子组件
var child = parent.$refs.child

内容分发

简单理解就是,父组件模板里的内容应该如何处置。

内容分发规则有如下几点:

  • 没有slot属性的内容分发给匿名slot

  • 有slot属性的内容分发给对应有相同name属性的slot

  • slot内的内容在没有被分发内容时显示,并不用任何标签进行包裹

组件组合方式

  • 父子组件

  • 递归组件

  • 循环引用组件(A组件套了B组件,B组件里又套了A,A引用B B引用A)

问题:
递归组件:组件递归调用自身时会进入死循环,因此须要用相似v-if,并最终v-if值最终返回false
循环引用组件:因为互相引用,致使引用关系混乱。在用webpack构建时,webpack没法判断先引用谁。如A引用B B引用A时首先致使混乱的是B组件。Vue提供了一个解决方法。

beforeCreate: function () {
  this.$options.components.TreeFolderContents = require('./B.vue')
}

组件通信

vue组件最长提的是解耦。每一个组件只负责本身的部分,他只关心接收的数据。因此我以为组件间的通信是vue组件最重要的部分。

父组件给子组件传递数据

父组件给子组件传递数据遵循一个模式。

  1. 在父组件模板中声明传入的数据

  2. 在子组件中用props属性接收传入的数据

这样一来,子组件彻底解耦,他只负责接收。

父组件模板传入

<child :message="hello!"></child>

在子组件接收

Vue.component('child', {
  // 声明 props
  props: ['message'],
  template: '<span>{{ message }}</span>'
})

说明:

  • 传入数据是基本类型时,在子组件修改props会报错

  • 传入数据是对象时,在子组件修改props的状况,由于对象是引用类型,修改props会同事修改到父组件

子组件通知父组件

子组件给父组件传递数据遵循一个模式。

  1. 在父组件模板绑定并监听一个事件,该事件触发父组件方法。

  2. 在子组件触发监听的事件,进而触发父组件方法,并把数据做为参数传入该方法。

具体实现:
在父组件模板监听事件

<div id="counter-event-example">
  <button-counter v-on:increment="incrementTotal"></button-counter>
</div>

在子组件触发事件

methods: {
  increment: function () {
    this.counter += 1
    this.$emit('increment', data)
  }
}

非父子组件通信

非父子组件通信,因为两个组件独立存在,不能像父子间那样在父模板传入或监听。

非父子组件通信经过eventBus也就是一个空的vue实例对象做为中转站进行通信。具体实现以下。

  1. 建立一个空的vue实例

  2. 在组件生命周期前期(一般是mounted)在中转站上声明一个事件监听,表示谁触发这个事件就至关于通知我了。

  3. 在另外一个组件,触发这个事件,和子通知父同样。

因此非父子和子传父的区别在于,声明监听事件的方式不一样。

具体实现:
建立一个中转站

var eventBus = new Vue()

在A组件声明周期内,在中转站监听一个事件,并把该事件中的this指向自身(A组件自己)

mounted: function () {
    eventBus.$on('addBar', function () {
        this.a++
    }.bind(this))
}

在B组件中触发事件来通知A组件

methods: {
    aaaAdd: function () {
        eventBus.$emit('addBar')
    }
}

slot内传入数据

与父传子同样的模式,在slot传入,在分发内容接收。

具体实现:
传入

<div class="child">
  <slot :text="msg"></slot>
</div>

接收,具备特殊属性 scope 的 <template> 元素必须存在

<div class="parent">
  <child>
    <template scope="props">
      <span>hello from parent</span>
      <span>{{ props.text }}</span>
    </template>
  </child>
</div>

有没有发现?四种不一样的通信方式各不相同,用了四种不一样的模式,并且有些在html文档里声明数据传入,有些在js文档里。我觉的很不优雅也不易理解和管理。

动态切换组件并缓存组件

原理很简单,经过内置的component元素绑定is来实现切换。

<component v-bind:is="currentView">
  <!-- 组件在 vm.currentview 变化时改变! -->
</component>

可是切换出去的组件不会被缓存,从新切回来会从新渲染,若是想缓存。

<keep-alive>
  <component :is="currentView">
    <!-- 非活动组件将被缓存! -->
  </component>
</keep-alive>
相关文章
相关标签/搜索