Vue官网教程学习笔记V2

# vue hello world
npm安装vue然后在html中导入
dom:
<div id="app">
  {{ message }}
</div>

js:
组件:
Vue.component('todo-item', {  
  props: ['todo'],
  template: '<li>{{ todo.text }}</li>'
})
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  },
  created: function () {
    // `this` 指向 vm 实例
    console.log('a is: ' + this.a)
  }
})

# 常用指令
HTML attribute v-bind:title="message"
条件渲染 v-if="seen"
显示隐藏 v-show
循环 v-for="todo in todos" :key="item.id"
点击 v-on:click="reverseMessage" @click="func"
双向绑定 <input v-model="message"> 实际是语法糖
一次性插值 <span v-once>这个将不会改变: {{ msg }}</span>

# Object.freeze(obj)
阻止修改现有的属性,也意味着响应系统无法再追踪变化。
obj必须是对象,阻止修改现有的属性不能阻止对象改写

# 小技巧:字符串反转 this.message = this.message.split('').reverse().join('')

# vue项目是基于组件的框架
组件系统是vue的一种抽象,特点是:小型、独立和通常可复用
几乎任意类型的应用界面都可以抽象为一个组件树

# vue支持IE9 及更高版本

# vue实例生命周期钩子
创建挂载更新销毁
created mounted updated destroyed
beforeCreate beforeMount beforeUpdate beforeDestroy

# 不要在选项属性或回调上使用箭头函数,比如 created: () => console.log(this.a) 或
vm.$watch('a', newValue => this.myMethod())。
因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 

# 在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。
结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
如果你熟悉虚拟 DOM 并且偏爱 JavaScript 的原始力量,你也可以不用模板,
直接写渲染 (render) 函数,使用可选的 JSX 语法

# 模板 所有模板都支持单个表达式(不支持if支持?:三目表达式)
文本: Mustache语法 (双大括号) 

原始 HTML
<span v-html="rawHtml"></span>
会忽略解析属性值中的数据绑定
不能使用 v-html 来复合局部模板,不是基于字符串的模板引擎,建议使用组件

HTML attribute:v-bind:id="dynamicId"
HTML attribute接受布尔类型时,会把表达式的值转化为布尔

# 指令
指令 (Directives) 是带有 v- 前缀的特殊 attribute。
指令 attribute 的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。
指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM

# HTML attribute
动态参数 <a v-bind:[attributeName]="url"> ... </a>
attributeName异常情况下值为 null用于移除绑定

attributeName可以是变量、表达式(不含空格引号)或者计算属性

在 DOM 中使用模板时 (直接在一个 HTML 文件里撰写模板),还需要避免使用大写字符来命名键名,
因为浏览器会把 attribute 名全部强制转为小写:
错误 <a v-bind:[someAttr]="value"> ... </a>
正确 <a v-bind:[someattr]="value"> ... </a>

# 一些指令的缩写
<a v-bind:href="url">...</a>
<a :href="url">...</a>

<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>

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

<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>

# 计算属性:复杂逻辑,你都应当使用计算属性
设计它们的初衷是用于简单运算的,模板中放入太多的逻辑会让模板过重且难以维护
计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解

计算属性缓存 vs 方法:
根据响应式依赖进行缓存
如果你不希望有缓存,请用方法
Date.now() 不是响应式依赖

# 为什么需要缓存
假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。
然后我们可能有其他的计算属性依赖于 A。
如果没有缓存,我们将不可避免的多次执行 A 的 getter!

# 计算属性的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]
    }
  }
}

# 侦听器被计算属性替代的一个场景
watch: {
	firstName: function (val) {
	  this.fullName = val + ' ' + this.lastName
	},
	lastName: function (val) {
	  this.fullName = this.firstName + ' ' + val
	}
}
computed: {
	fullName: function () {
	  return this.firstName + ' ' + this.lastName
	}
}

# 监(侦)听器对vs计算属性
监听器适合做异步请求,设置中间状态,或者进行开销较大的操作
计算属性做不到

# class绑定
:class="{ active: isActive, 'text-danger': hasError }"
:class="classObject" classObject可以是对象或者计算属性

:class="[activeClass, errorClass]" 字符串数组
:class="[isActive ? activeClass : '', errorClass]" 表达式

:class="[{ active: isActive }, errorClass]" 数组包含对象

组件上class 属性将被合并到组件根元素上

# style绑定
v-bind:style 的绑定值是一个 JavaScript 对象。
CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

:style="styleObject" 对象语法

:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }" 浏览器选择性回退

# 条件渲染
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>

v-else 元素必须紧跟在带 v-if 或者 v-else-if(2.1.0 新增) 的元素的后面,否则它将不会被识别

使用key重新传染input,输入的值会被清空
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

v-show 只是简单地切换元素的 CSS 属性 display,元素始终会被渲染并保留在 DOM 中
v-show 不支持 <template> 元素,也不支持 v-else

v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好

# 列表渲染
v-for="(item, index) in items"
v-for="item in items" v-bind:key="item.id"
用字符串或数值类型的值作为 v-for 的 key,避免使用对象或数组之类的非基本类型值

数组元素顺序改变时,Vue就地更新每个元素而不会移动DOM 元素
Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的启发式方法,
所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。

变异方法 (mutation method)
Vue 将被侦听的数组的变异方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
splice push pop shift unshift
sort reverse

非变异 (non-mutating method) 方法,例如 filter()、concat() 和 slice() 。
它们不会改变原始数组,而总是返回一个新数组
当使用非变异方法时,可以用新数组替换旧数组

对象渲染
v-for="value in object"
v-for="(value, name) in object"

# 数组监听限制:Vue 不能检测用下标访问并修改元素,修改数组长度
修改元素
Vue.set(vm.items, indexOfItem, newValue)
vm.$set(vm.items, indexOfItem, newValue)
vm.items.splice(indexOfItem, 1, newValue)

修改长度
vm.items.splice(newLength)

# 对象监听限制:Vue 不能检测对象属性的添加或删除

Vue.set(object, propertyName, value)
Vue.set(vm.userProfile, 'age', 27)
vm.$set(vm.userProfile, 'age', 27)

为已有对象赋值多个新属性
vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

错误:
Object.assign(vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

显示过滤/排序后的结果
v-for="n in evenNumbers" evenNumbers计算属性
v-for="n in even(numbers)" even方法

在 v-for 里使用值范围
<span v-for="n in 10">{{ n }} </span>

两个两个循环,以前总是用div作为父节点包裹,造成层级过多
<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>

# 不推荐在同一元素上使用 v-if 和 v-for
当它们处于同一节点,v-for 的优先级比 v-if 更高
v-for="todo in todos" v-if="!todo.isComplete"

# 2.2.0+ 的版本里,当在组件上使用 v-for 时,key 现在是必须的
任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。
使用prop把迭代数据传递到组件里

# 在 <ul> 元素内只有 <li> 元素会被看作有效内容,<todo-item>无法识别,用动态组件
<li
  is="todo-item"
  v-for="(todo, index) in todos"
  v-bind:key="todo.id"
  v-bind:title="todo.title"
  v-on:remove="todos.splice(index, 1)"
></li>

# 事件默认回调参数是事件对象event
内联 v-on:click="say('hi')"
特殊变量 $event v-on:click="warn('Form cannot be submitted yet.', $event)" warn: function (message, event)
event.preventDefault() 或 event.stopPropagation()

<!-- 阻止单击事件继续传播 -->
<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>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

<!-- 点击事件将只会触发一次 --> .once 修饰符还能被用到自定义的组件事件上
<a v-on:click.once="doThis"></a> 

addEventListener 中的 passive 选项提供了 .passive 修饰符,告诉浏览器你不想阻止事件的默认行为。

v-on:click.prevent.self 会阻止所有的点击,
而 v-on:click.self.prevent 只会阻止对元素自身的点击

v-on:keyup.page-down="onPageDown"
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
有一些按键 (.esc 以及所有的方向键) 在 IE9 中有不同的 key 值, 
如果你想支持 IE9,这些内置的别名应该是首选

按键别名设置 Vue.config.keyCodes.f1 = 112

# 系统修饰键 
.ctrl
.alt
.shift
.meta

例子:
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

修饰键 在和 keyup 事件一起用时必须处于按下状态

.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>

keyCode 的事件用法已经被废弃了并可能不会被最新的浏览器支持 v-on:keyup.13="submit"

# 鼠标按钮修饰符 仅响应特定的鼠标按钮
.left
.right
.middle

# 在 HTML 中监听事件?
HTML中方便一眼看出绑定哪些方法
无须在 JavaScript 里手动绑定事件,代码只关注逻辑,和 DOM 完全解耦,更易于测试
ViewModel 被销毁时,所有的事件处理器都会自动被删,无须手动清理

# 输入法组合文字过程不会触发v-model,会触发input 事件
v-model 会忽略所有表单元素的 value、checked、selected

v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
text 和 textarea 元素使用 value 属性和 input 事件;
checkbox 和 radio 使用 checked 属性和 change 事件;
select 使用 value 属性和 change 作为事件

<textarea>{{text}}</textarea> 并不会生效

# 单选按钮通常是静态字符串
<input type="radio" v-model="picked" value="a">

# 复选框模式是布尔值,也可以是静态字符串
布尔值
<input type="checkbox" v-model="toggle"> true false

静态字符串
<input
  type="checkbox"
  v-model="toggle"
  true-value="yes"
  false-value="no"
>

浏览器在提交表单时并不会包含未被选中的复选框,用单选按钮才能确保提交一个
多个复选框可以绑定到同一个数组Checked names: [ "Jack", "John", "Mike" ]

# 选择框可以是静态字符串或者对象
<select v-model="selected">
  <option value="abc">ABC</option>
</select>

内联对象字面量
<select v-model="selected">
  <option v-bind:value="{ number: 123 }">123</option>
</select>

v-model 表达式的初始值未能匹配任何选项,<select> 元素将被渲染为“未选中”状态
iOS 不会触发 change 事件,推荐提供一个值为空的禁用选项。
<select v-model="selected">
	<option disabled value="">请选择</option>
	<option>A</option>
	<option>B</option>
	<option>C</option>
</select>


# .lazy使用 change 事件而不是input进行同步
<input v-model.lazy="msg" >

# .number
这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。
如果这个值无法被 parseFloat() 解析,则会返回原始的值
<input v-model.number="age" type="number">

# .trim
过滤用户输入的首尾空白字符 <input v-model.trim="msg">

# 组件参数
data 必须是一个函数,每个实例可以维护一份被返回对象的独立的拷

# 组件注册类型:全局注册和局部注册
全局注册
Vue.component('my-component-name', {
  // ... options ...
})

每个组件必须只有一个根元素	

事件传递
$emit('enlarge-text'[, 0.1])
v-on:enlarge-text="postFontSize += 0.1" 或者 onEnlargeText: function (enlargeAmount)

插槽
在组件中定义<slot></slot>
使用时 
<alert-box>
  Something bad happened.
</alert-box>

# is attribute 
<component v-bind:is="currentTabComponent"></component>
已注册组件的名字,或
一个组件的选项对象

# 动态组件属性?
这个 attribute 可以用于常规 HTML 元素,但这些元素将被视为组件,
这意味着所有的 attribute 都会作为 DOM attribute 被绑定。
对于像 value 这样的 property,若想让其如预期般工作,你需要使用 .prop 修饰器。

# v-bind绑定对象
v-bind="$attrs"
v-bind="object"

# 向父组件发送消息
button v-on:click="$emit('enlarge-text', 0.1)"

# v-model在input上的原理
<input
  v-bind:value="value"
  v-on:input="$emit('input', $event.target.value)"
>

# 有些 HTML 元素,诸如 <ul>、<ol>、<table> 和 <select>,对于哪些元素可以出现在其内部是有严格限制的。
而有些元素,诸如 <li>、<tr> 和 <option>,只能出现在其它某些特定的元素内部。
动态组件解决:
<table>
  <tr is="blog-post-row"></tr>
</table>

# 局部注册的组件在其子组件中不可用

# 组件注册类型
全局注册
Vue.component('my-component-name', {
  // ... 选项 ...
})

局部注册
var ComponentA = { /* ... */ }
var ComponentB = {
  components: {
    'component-a': ComponentA
  },
  // ...
}

Babel 和 webpack 的模块系统中局部注册
import ComponentA from './ComponentA'
import ComponentC from './ComponentC'
export default {
  components: {
    ComponentA,
    ComponentC
  },
  // ...
}


基础组件自动注册,使用基于webpack的require.context
require.context

# Prop 的大小写 (camelCase vs kebab-case)
HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。
这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名

# 单向数据流
传入只读数据,作为data里变量的初始值
作为计算属性的依赖

# Prop 验证
propA: Number,
String
Number
Boolean
Array
Object
Date
Function
Symbol
或者是自定义函数

propB: [String, Number]
propD: {
  type: Number,
  default: 100,
  required: true
}
// 带有默认值的对象
propE: {
  type: Object,
  // 对象或数组默认值必须从一个工厂函数获取
  default: function () {
	return { message: 'hello' }
  }
},
// 自定义验证函数
propF: {
  validator: function (value) {
	// 这个值必须匹配下列字符串中的一个
	return ['success', 'warning', 'danger'].indexOf(value) !== -1
  }
}

# 组件可以接受任意的 attribute,而这些 attribute 会被添加到这个组件的根元素上
class 和 style attribute 会稍微智能一些,即两边的值会被合并起来
方便集成第三方插件

# 禁用 Attribute 继承
Vue.component('my-component', {
  inheritAttrs: false,//不会影响 style 和 class 的绑定
  // ...
})
模板中使用v-bind="$attrs"可以绑定组件属性

# 自定义事件:推荐你始终使用 kebab-case 的事件名
this.$emit('myEvent')

# 自定义组件的 v-model
<input
  type="checkbox"
  v-bind:checked="checked"
  v-on:change="$emit('change', $event.target.checked)"
>
<base-checkbox v-model="lovingVue"></base-checkbox>

# 将原生事件绑定到组件
Vue.component('base-input', {
  inheritAttrs: false,
  props: ['label', 'value'],
  computed: {
    inputListeners: function () {
      var vm = this
      // `Object.assign` 将所有的对象合并为一个新对象
      return Object.assign({},
        // 我们从父级添加所有的监听器
        this.$listeners,
        // 然后我们添加自定义监听器,
        // 或覆写一些监听器的行为
        {
          // 这里确保组件配合 `v-model` 的工作
          input: function (event) {
            vm.$emit('input', event.target.value)
          }
        }
      )
    }
  },
  
在模板中使用:
<input
        v-bind="$attrs"
        v-bind:value="value"
        v-on="inputListeners"
      >
	  
# .sync 修饰符
<text-document v-bind:title.sync="doc.title"></text-document>
是对以下代码的简写:
this.$emit('update:title', newTitle)
<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>


# 插槽
不带v-slot指令会被插入到默认插槽
v-slot 只能添加在 <template> 上
默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确

后备内容:
<button type="submit">
  <slot>Submit</slot>
</button>

具名插槽
组件中:<slot name="header"></slot> ,不带 name 的 <slot> 出口会带有隐含的名字“default”
使用时: <template v-slot:header>xxx</template>, v-slot:default表示默认插槽

# 作用域插槽
组件:
<slot v-bind:user="user">
    {{ user.lastName }}
</slot>
使用:
<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

# 独占默认插槽的缩写语法
<current-user v-slot:default="slotProps">
  {{ slotProps.user.firstName }}
</current-user>
或者:
<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
</current-user>

# 解构插槽 Prop
<current-user v-slot="{ user }">
  {{ user.firstName }}
</current-user>

user 重命名为 person:
<current-user v-slot="{ user: person }">
  {{ person.firstName }}
</current-user>

定义后备内容:
<current-user v-slot="{ user = { firstName: 'Guest' } }">
  {{ user.firstName }}
</current-user>

# 动态插槽
<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>

# 具名插槽的缩写
v-slot:header 可以被重写为 #header

和其它指令一样,该缩写只在其有参数的时候才可用
<!-- 这样会触发一个警告 -->
<current-user #="{ user }">
  {{ user.firstName }}
</current-user>
正确:
<current-user #default="{ user }">
  {{ user.firstName }}
</current-user>

# 插槽作用域意义
插槽 prop 允许我们将插槽转换为可复用的模板,这些模板可以基于输入的 prop 渲染出不同的内容。
这在设计封装数据逻辑同时允许父级组件自定义部分布局的可复用组件时是最有用的

# 在动态组件上使用 keep-alive
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

# 异步组件
Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 向 `resolve` 回调传递组件定义
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

Vue.component('async-webpack-example', function (resolve) {
  // 这个特殊的 `require` 语法将会告诉 webpack
  // 自动将你的构建代码切割成多个包,这些包
  // 会通过 Ajax 请求加载
  require(['./my-async-component'], resolve)
})

Vue.component(
  'async-webpack-example',
  // 这个 `import` 函数会返回一个 `Promise` 对象。
  () => import('./my-async-component')
)

局部注册
new Vue({
  // ...
  components: {
    'my-component': () => import('./my-async-component')
  }
})

处理加载状态 2.3.0+ 新增
const AsyncComponent = () => ({
  // 需要加载的组件 (应该是一个 `Promise` 对象)
  component: import('./MyComponent.vue'),
  // 异步组件加载时使用的组件
  loading: LoadingComponent,
  // 加载失败时使用的组件
  error: ErrorComponent,
  // 展示加载时组件的延时时间。默认值是 200 (毫秒)
  delay: 200,
  // 如果提供了超时时间且组件加载也超时了,
  // 则使用加载失败时使用的组件。默认值是:`Infinity`
  timeout: 3000
})

在 Vue Router 的路由组件中使用上述语法的话,你必须使用 Vue Router 2.4.0+ 版本。

# 访问根实例 不推荐,建议用vuex
// 获取根组件的数据
this.$root.foo
// 写入根组件的数据
this.$root.foo = 2
// 访问根组件的计算属性
this.$root.bar
// 调用根组件的方法
this.$root.baz()

# 访问父级组件实例
this.$parent

# 访问子组件实例或子元素
this.$refs.usernameInput
$refs 只会在组件渲染完成之后生效,并且它们不是响应式的
避免在模板或计算属性中访问 $refs

# 依赖注入
父组件
provide: function () {
  return {
    getMap: this.getMap
  }
}
后代组件,不限层级
inject: ['getMap']
依赖注入将你应用程序中的组件与它们当前的组织方式耦合起来,使重构变得更加困难
同时所提供的属性是非响应式的

# 程序化的事件侦听器
mounted: function () {
  this.attachDatepicker('startDateInput')
  this.attachDatepicker('endDateInput')
},
methods: {
  attachDatepicker: function (refName) {
    var picker = new Pikaday({
      field: this.$refs[refName],
      format: 'YYYY-MM-DD'
    })

    this.$once('hook:beforeDestroy', function () {
      picker.destroy()
    })
  }
}

# 递归组件
name: 'stack-overflow',
template: '<div><stack-overflow></stack-overflow></div>'
没有出口会导致内存溢出

这个例子需要测试下:
<p>
	<span>{{ folder.name }}</span>
	<ul>
		<li v-for="child in folder.children">
			<tree-folder v-if="child.children" :folder="child"/>
			<span v-else>{{ child.name }}</span>
		</li>
	</ul>
</p>

# 组件之间的循环引用
<tree-folder> 组件
<p>
  <span>{{ folder.name }}</span>
  <tree-folder-contents :children="folder.children"/>
</p>

<tree-folder-contents> 组件
<ul>
  <li v-for="child in children">
    <tree-folder v-if="child.children" :folder="child"/>
    <span v-else>{{ child.name }}</span>
  </li>
</ul>

在渲染树中互为对方的后代和祖先,报错:
Failed to mount component: template or render function not defined.
解决:
Vue.component 全局注册组件

或者:
beforeCreate: function () {
  this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
}

或者使用 webpack 的异步 import:
components: {
  TreeFolderContents: () => import('./tree-folder-contents.vue')
}

# 内联模板inline-template 使用子元素作为组件模板
<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>

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

# 强制更新,那么你可以通过 $forceUpdate 来做这件事
没有留意到数组或对象的变更检测注意事项,或者你可能依赖了一个未被 Vue 的响应式系统追踪的状态

# 通过 v-once 创建低开销的静态组件
在根元素上添加 v-once attribute 
渲染大量静态内容时速度变慢了才有必要使用v-once模式
v-once导致自动更新数据失败,有时难以发现问题

# 混入mixin
分发 Vue 组件中的可复用功能
mixins: [myMixin]
数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先
同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。

# 全局混入影响每一个之后创建的 Vue 实例
Vue.mixin({
  created: function () {
    var myOption = this.$options.myOption
    if (myOption) {
      console.log(myOption)
    }
  }
})

# 自定义选项合并策略
Vue.config.optionMergeStrategies 添加一个函数

# 注册全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el,binding) {
    // 聚焦元素
    el.focus()
  }
})

# 注册局部指令,组件中也接受一个 directives 的选项:
directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}

# 指令的钩子函数
bind指令第一次绑定到元素
unbind指令与元素解绑
inserted被绑定元素插入父节点时,仅保证父节点存在,不一定已被插入文档中
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
update组件的 VNode 更新时,不确定指令值是否改变

# 指令钩子函数会被传入以下参数:除了 el 之外,其它参数都应该是只读
el:指令所绑定的DOM
binding:一个对象,包含以下属性,以v-my-directive:foo.a.b="1 + 1"为例子
{
	name指令名不含v-:my-directive
	arg指令参数:foo
	modifiers指令修饰符的对象:{a:true,b:true}
	expression指令表达式字符串:"1 + 1"
	value指令表达式返回值:2
	oldValue前一个值,仅在 update 和 componentUpdated 钩子中可
}
vnode虚拟节点
oldVnode:上一个虚拟节点

# 动态指令参数
v-mydirective:[argument]="value" argument 可改变
例如:
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    var s = (binding.arg == 'left' ? 'left' : 'top')
    el.style[s] = binding.value + 'px'
  }
})

函数简写:bind 和 update 时触发相同行
Vue.directive('color-swatch', function (el, binding) {
  el.style.backgroundColor = binding.value
})

# render函数
程序化生成dom:灵活,简洁,局部变量
例如:
Vue.component('anchored-heading', {
  render: function (createElement) {
    return createElement(
      'h' + this.level,   // 标签名称
      this.$slots.default // 子节点数组
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})

# createElement 
虚拟节点 (virtual node)”,也常简写它为“VNode”。
虚拟 DOM: VNode 树

最简单的用法 createElement('hello') 生成文本节点vnode

createElement(参数1,参数2,参数3)
参数1:String | Object | Function
一个 HTML 标签名、组件选项对象,
或者resolve 了上述任何一种的一个 async 函数。必填项

参数2:Object
数据对象,即一个与模板中属性对应的数据对象

参数3:String | Array
子级虚拟节点 (VNodes),由 `createElement()` 构建而成,
或者使用字符串来生成“文本虚拟节点”。可选。


# 数据对象
{
  // 与 `v-bind:class` 的 API 相同,接受一个字符串、对象或字符串和对象组成的数组
  'class': {
    foo: true,
    bar: false
  },
  // 与 `v-bind:style` 的 API 相同,接受一个字符串、对象,或对象组成的数组
  style: {
    color: 'red',
    fontSize: '14px'
  },
  // 普通的 HTML attribute
  attrs: {
    id: 'foo'
  },
  // 组件 prop
  props: {
    myProp: 'bar'
  },
  // DOM 属性
  domProps: {
    innerHTML: 'baz'
  },
  // 事件监听器在 `on` 属性内,
  // 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
  // 需要在处理函数中手动检查 keyCode。
  on: {
    click: this.clickHandler
  },
  // 仅用于组件,用于监听原生事件,而不是组件内部使用
  // `vm.$emit` 触发的事件。
  nativeOn: {
    click: this.nativeClickHandler
  },
  // 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
  // 赋值,因为 Vue 已经自动为你进行了同步。
  directives: [
    {
      name: 'my-custom-directive',
      value: '2',
      expression: '1 + 1',
      arg: 'foo',
      modifiers: {
        bar: true
      }
    }
  ],
  // 作用域插槽的格式为
  // { name: props => VNode | Array<VNode> }
  scopedSlots: {
    default: props => createElement('span', props.text)
  },
  // 如果组件是其它组件的子组件,需为插槽指定名称
  slot: 'name-of-slot',
  // 其它特殊顶层属性
  key: 'myKey',
  ref: 'myRef',
  // 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
  // 那么 `$refs.myRef` 会变成一个数组。
  refInFor: true
}

# VNode 必须唯一
下面的渲染函数是不合法的:
render: function (createElement) {
  var myParagraphVNode = createElement('p', 'hi')
  return createElement('div', [
    // 错误 - 重复的 VNode
    myParagraphVNode, myParagraphVNode
  ])
}

渲染了 20 个相同的段落
render: function (createElement) {
  return createElement('div',
    Array.apply(null, { length: 20 }).map(function () {
      return createElement('p', 'hi')
    })
  )

}

# JSX
import AnchoredHeading from './AnchoredHeading.vue'
new Vue({
  el: '#demo',
  render: function (h) {
    return (
      <AnchoredHeading level={1}>
        <span>Hello</span> world!
      </AnchoredHeading>
    )
  }
})

# 函数式组件
无状态 (没有响应式数据),也没有实例 (没有 this 上下文
Vue.component('my-component', {
  functional: true,
  // Props 是可选的
  props: {
    // ...
  },
  // 为了弥补缺少的实例this
  // 提供第二个参数作为上下文context
  render: function (createElement, context) {
    // ...
  }
})

# 使用插件
Vue.use(MyPlugin)
Vue.use(MyPlugin, { someOption: true })


// 用 Browserify 或 webpack 提供的 CommonJS 模块环境时
var Vue = require('vue')
var VueRouter = require('vue-router')
// 不要忘了调用此方法
Vue.use(VueRouter)

开发插件
Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象
MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或属性
  Vue.myGlobalMethod = function () {
    // 逻辑...
  }

  // 2. 添加全局资源 指令/过滤器/过渡
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      // 逻辑...
    }
    ...
  })

  // 3. 注入组件选项
  Vue.mixin({
    created: function () {
      // 逻辑...
    }
    ...
  })

  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...
  }
}

可以提供其中一个功能或者多个功能


# 过滤器可以用在两个地方:双花括号插值和 v-bind 表达式
{{ message | capitalize }}
<div v-bind:id="rawId | formatId"></div>

你可以在一个组件的选项中定义本地的过滤器:
filters: {
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}
或者在创建 Vue 实例之前全局定义过滤器:
Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

new Vue({
  // ...
})
当全局过滤器和局部过滤器重名时,会采用局部过滤器

过滤器可以串联:
{{ message | filterA | filterB }}

不使用单文件组件的问题:
全局定义 (Global definitions) 强制要求每个 component 中的命名不得重复
字符串模板 (String templates) 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的 \
不支持 CSS (No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
没有构建步骤 (No build step) 限制只能使用 HTML 和 ES5 JavaScript,而不能使用预处理器,如 Pug (formerly Jade) 和 Babel

使用单文件可以获得:
完整语法高亮
CommonJS 模块
组件作用域的 CSS

关注点分离?
一个重要的事情值得注意,关注点分离不等于文件类型分离。
在现代 UI 开发中,我们已经发现相比于把代码库分离成三个大的层次并将其相互交织起来,
把它们划分为松散耦合的组件再将其组合起来更合理一些。
在一个组件里,其模板、逻辑和样式是内部耦合的,并且把他们搭配在一起实际上使得组件更加内聚且更可维护。

不喜欢单文件组件,你仍然可以把 JavaScript、CSS 分离成独立的文件然后做到热重载和预编译。

# DOM 更新完成后被调用
this.$nextTick(function () {
	console.log(this.$el.textContent) // => '已更新'
})

# vue过渡 页面路由过渡效果
Vue 插入/更新/移除元素时自动应用过渡效果
当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理:
自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。
如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。
如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。
(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同)

类名:支持自定义过渡的类名,可以在属性中声明 JavaScript 钩子
v-enter,v-enter-active,v-enter-to,
v-leave,v-leave-active,v-leave-to
<transition name="slide-fade">
	<p v-if="show">hello</p>
</transition>

使用css动画
<transition name="bounce">
  <p v-if="show">hello</p>
</transition>

css:
.bounce-enter-active {
  animation: bounce-in .5s;
}
.bounce-leave-active {
  animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(1);
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值