title: vue文档-基础
date: 2018.9.3
tags:
# B 深入了解组件
[x] 过滤器
[ ] 风格指南
2018.9.3 星期一
2018.11.2 星期五 10:28 2nd
1. Vue.js 是什么
1. 起步
1. 声明式渲染
1. 条件与循环
1. 处理用户输入
1. 组件化应用构建
1. 与自定义元素的关系
1. 准备好了吗?
创建一个 Vue 实例
数据与方法
实例生命周期钩子
生命周期钩子的 this 上下文指向调用它的 Vue 实例。
不要在选项属性或回调上使用箭头函数,因为箭头函数是和父级上下文绑定在一起的,this 不会是如你所预期的 Vue 实例,
beforeCreate,created, beforeMount,mounted, beforeDestroy,destroyed
beforeUpdate,updated
$PS_react生命周期: constructor,getDerivedStateFromProps,render,componentDidMount,componentWillUnmount, shouldComponentUpdate,getSnapsBeforeUpdate,componentDidUpdate
组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的:
0 取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
1 通过 Prop 向子组件传递数据
2 通过事件向父级组件发送消息
Vue 实例提供了一个自定义事件的系统来解决这个问题。我们可以调用内建的 $emit 方法并传入事件的名字,来向父级组件触发一个事件:
$emit 的第二个参数来提供这个值,在父级组件监听这个事件的时候,我们可以通过 $event 访问到被抛出的这个值
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
v-on:enlarge-text="postFontSize += 0.1"
v-on:enlarge-text="onEnlargeText" // ### 传递值
></blog-post>
// ### 传递值
methods: {
onEnlargeText: function (enlargeAmount) {
this.postFontSize += enlargeAmount
}
}
// 全局定义
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
<button v-on:click="$emit('enlarge-text,0.1')"> Enlarge text </button>
</div>
`
})
### 在组件上使用 v-model
### 通过插槽分发内容
### 动态组件 is <component v-bind:is="currentTabComponent"></component>
### 解析 DOM 模板时的注意事项
幸好这个特殊的 is 特性给了我们一个变通的办法:
需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:
<script type="text/x-template">
全局注册Vue.component 在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。
局部注册 然后在 components 选项中定义你想要使用的组件 注意局部注册的组件在其子组件中不可用,也需要在components选项中定义要使用的组件($PS:全局注册的不需要)
### 模块系统
通过 import/require 使用一个模块系统,
局部注册:然后你需要在局部注册之前导入每个你想使用的组件。
基础组件的自动化全局注册:幸好如果你使用了 webpack (或在内部使用了 webpack 的 Vue CLI 3+),那么就可以使用 require.context 只全局注册这些非常通用的基础组件。
### 单向数据流
###
### Prop 验证
Vue.component('my-component',{
props:{
propA:Number,/[String, Number],/{type:7类型/自定义构造函数,require,default:type/funciton,validator,}
}
})
### 非 Prop 的特性
一个非 prop 特性是指传向一个组件,但是该组件并没有相应 prop 定义的特性。
因为显式定义的 prop 适用于向一个子组件传入信息,然而组件库的作者并不总能预见组件会被用于怎样的场景。这也是为什么组件可以接受任意的特性,而这些特性会被添加到这个组件的根元素上。
### 替换/合并已有的特性
对于绝大多数特性来说,从外部提供给组件的值会替换掉组件内部设置好的值。庆幸的是,class 和 style 特性会稍微智能一些,即两边的值会被合并起来,从而得到最终的值:
### 禁用特性继承
如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false
### 事件名
同于组件和 prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。
不同于组件和 prop,事件名不会被用作一个 JavaScript 变量名或属性名,所以就没有理由使用 camelCase 或 PascalCase 了。并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的)
因此,我们推荐你始终使用 kebab-case 的事件名。
### 自定义组件的 v-model
### 将原生事件绑定到组件
### .sync 修饰符
具名插槽: 有些时候我们需要多个插槽。
在一个父组件的 元素上使用 slot 特性:
另一种 slot 特性的用法是直接用在一个普通的元素上:
我们还是可以保留一个未命名插槽,这个插槽是默认插槽,也就是说它会作为所有未匹配到插槽的内容的统一出口。
### 插槽的默认内容: 如果父组件为这个插槽提供了内容,则默认的内容会被替换掉。
### 编译作用域: 该插槽可以访问跟这个模板的其它地方相同的实例属性
父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译
### 作用域插槽
一个指令定义对象可以提供如下几个钩子函数 (均为可选):bind,inserted,update,componentUpdated,unbind.
指令钩子函数会被传入以下参数:el,binding:{name,value,oldvalue,expression,arg,modifiers},vnode,oldvalue
除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。
### 函数简写:你可能想在 bind 和 update 时触发相同行为,而不关心其它的钩子
### 对象字面量
如果指令需要多个值,可以传入一个 JavaScript 对象字面量。记住,指令函数能够接受所有合法的 JavaScript 表达式。// ## 1 全局 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { inserted: function (el) { el.focus() } }) // ## 2 如果想注册局部指令,组件中也接受一个 directives 的选项: directives: { focus: { inserted: function (el) { el.focus() } } }
$LUE
过滤器可以用在两个地方:双花括号插值和 v-bind 表达式
// ## 2 你可以在一个组件的选项中定义本地的过滤器:
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
// ## 1 或者在创建 Vue 实例之前全局定义过滤器:
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
### 不使用构建工具
### 使用构建工具: webpack 或 Browserify 类似的构建工具时,Vue 源码会根据 process.env.NODE_ENV ;Rollup 使用 rollup-plugin-replace:
### 模板预编译
预编译模板最简单的方式就是使用单文件组件——相关的构建设置会自动把预编译处理好,所以构建好的代码已经包含了编译出来的渲染函数而不是原始的模板字符串。
### 提取组件的 CSS
当使用单文件组件时,组件内的 CSS 会以 <style>
标签的方式通过 JavaScript 动态注入。
将所有组件的 CSS 提取到同一个文件可以避免这个问题,也会让 CSS 更好地进行压缩和缓存。 webpack + vue-loader,其他..
### 跟踪运行时错误
我们使用 Vue.component 来定义全局组件,紧接着用 new Vue({ el: '#container '})
在每个页面内指定一个容器元素。
单文件组件: 完整语法高亮,CommonJS 模块,组件作用域的 CSS
可以使用预处理器来构建简洁和功能更丰富的组件
### 怎么看待关注点分离?
关注点分离不等于文件类型分离。
在一个组件里,其模板、逻辑和样式是内部耦合的,并且把他们搭配在一起实际上使得组件更加内聚且更可维护。
即便你不喜欢单文件组件,你仍然可以把 JavaScript、CSS 分离成独立的文件然后做到热重载和预编译。
官方 vue-router, 整合第三方如 Page.js 或者 Director
$TODO: vue-router
类 Flux 状态管理的官方实现:vuex
Redux 事实上无法感知视图层,所以它能够轻松的通过一些简单绑定和 Vue 一起使用。Vuex 区别在于它是一个专门为 Vue 应用所设计。这使得它能够更好地和 Vue 进行整合,同时提供简洁的 API 和改善过的开发体验。
1) vue 应用中原始数据对象的实际来源 - 当访问数据对象时,一个 Vue 实例只是简单的代理访问。所以,如果你有一处需要被多个实例间共享的状态,可以简单地通过维护一份数据来实现共享
2) 为了解决这个问题,我们采用一个简单的 store 模式:
此外,每个实例/组件仍然可以拥有和管理自己的私有状态:
2) 接着我们继续延伸约定,组件不允许直接修改属于 store 实例的 state,而应执行 action 来分发 (dispatch) 事件通知 store 去改变,我们最终达成了 Flux 架构。这样约定的好处是,我们能够记录所有 store 中发生的 state 改变,同时实现能做到记录变更 (mutation)、保存状态快照、历史回滚/时光旅行的先进的调试工具。
$BLOB: vuejs文档-深入响应式原理
### 检测变化的注意事项
受现代 JavaScript 的限制 (而且 Object.observe 也已经被废弃),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
### 声明响应式属性
由于 Vue 不允许动态添加根级响应式属性,所以你必须在初始化实例前声明根级响应式属性,哪怕只是一个空值:
### 异步更新队列
Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。
Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MessageChannel,如果执行环境不支持,会采用 setTimeout(fn, 0) 代替。
1) 全局 $PS: 不采用
2) 在组件内使用 vm.$nextTick() 实例方法特别方便,因为它不需要全局 Vue ,并且回调函数中的 this 将自动绑定到当前的 Vue 实例上:
$PS: angularjs: $scope.$apply(function(){$scope.data=newData})
3) 因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的 ES2016 async/await 语法完成相同的事情
Vue.component('example', {
template: '<span>{{ message }}</span>',
data: function () {
return {
message: '没有更新'
}
},
methods: { // 2 this.$nextTick(callback)
updateMessage: function () {
this.message = '更新完成'
console.log(this.$el.textContent) // => '没有更新'
this.$nextTick(function () {
console.log(this.$el.textContent) // => '更新完成'
})
}
},
methods: { // 3 async/await
async updateMessage: function () {
this.message = 'updated'
console.log(this.$el.textContent) // => '未更新'
await this.$nextTick()
console.log(this.$el.textContent) // => '已更新'
}
}
})