基础
-
组件树
Vue.component('todo-item', { prop: ['todo'], //自定义特性 template: '<li> {{ todo.text }}</li>' }) -
当一个实例被创建时,它将data对象中所有的属性加入到 Vue的 【响应式系统】中,即双向绑定
-
设置对象为只读属性
Object.freeze(), 冻结一个对象,不能进行操作 -
生命周期 created mounted ... 禁止在选项属性或回调上使用
箭头函数: created: () => console.log(this.a) undefined -
命令
-
v-html: 原始html,双大括号只会解析为数据 你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。 请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
-
xxx: null undefined false 类似 为false。
-
{{ ok ? "true" : "false" }} 只能设置单个表达式
-
计算属性
computed: { reverseMessage: function(val){ //val === this : true return this.message.split("") ; //原理: get set }, // 该属性添加到this上 fll_name: { get(){} , // set(){} } } methods: { reverseMessage: function (){ return this.message.split("") } } 两种方式获取的结果一致,但是【计算属性是基于它们响应式依赖进行-----缓存----的】 只在相关响应式依赖发生改变时它们才会重新求值。 这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果, 而不必再次执行函数。 -
监听属性
watch:{ first_name: function (val, old_val){ val;新值 old_val: 旧值 } } -
计算、监听属性,本质区别: 一个新添加一个变量, 一个监听一个变量
-
侦听器
- 当数据变化时执行异步或者开销较大的操作时,这个方式最有用
_.debounce是一个通过 Lodash 限制操作频率的函数。_.throttle
https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js created: function(){ this.debounceGetAnswer = _.debounce(this.getAnswer, 500) ; //函数防抖 } methods:{ getAnswer(){} } -
列表渲染
-
v-for,必要提供key
-
注意事项
不能检测到以下 事件, 其他可以 1. 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue 2. 当你修改数组的长度时,例如:vm.items.length = newLength 3. 不是响应式的 arr[0] = "xxx" arr.length = x 4,解决方法 this.$set(value, index, newValue) ; //Vue set this.value.splice(0 , 1, newValue) ; //修改原数组 3,对象变更机制 vm.b = "cc" //后添加的属性 不是响应式的
-
-
组件之间相互不影响
注册组件:全局注册、局部注册
全局注册
Vue.component('xx', {
data: function(){} //必须是一个函数
})
在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。可以被嵌套
局部注册
let a = {
template: '<div></div' //有且仅有一个父元素
},b = {} ;
new Vue({
components: {
a, b
}
})
局部注册的组件在其子组件中不可用
15,父子组件之间传递数据
1,props 传递, 自定义属性
单向数据流 父 --> 子
<v-title title="xx"/>
Vue.com....{
props: ['title']
}
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
不能 更改 prop的值
1,这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。
在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
2,这个 prop 以一种原始的值传入且需要进行转换。
在这种情况下,最好使用这个 prop 的值来定义一个计算属性:
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
3,prop验证
props:{
data: [Number,String ...] ,
data_t: {
type: String,
required: true,
default: 100
}
}
4, 非prop的特性
一个非prop特性指向一个组件,该属性加入到根元素上
6,prop的双向绑定
1,发布者订阅者模式
父组件:订阅者 <component @my-event="change()"/>
子组件:发布者 this.$emit('my-event', 参数)
change($event){
$event //子组件传过来的参数
}
2,.sync 操作符
不能和表达式一起使用::title.sync = "doc.title = 'xxx' " ;
子组件:
this.$emit('update:title', 'Son') ;
父组件:
<component :title.sync = "title" />
原因: :title.sync 类似语法糖---> @update:title = "data = > title = data" :title = "title"
16,插槽 ( 内容分发的API,将slot元素作为承载分发内容的出口 )
1,<slot > :提供给子组件使用
v-slot slot和slot-scope 已被丢弃
<component>
<div>插入的内容</div>
</component>
<template>
<slot></slot>
</template>
2,编译作用域
父级模板里的所有内容都是在父级作用域中编译的;
子模板里的所有内容都是在子作用域中编译的。
<div :data = "父"/>
3,后备内容
<slot>
<div>当父组件没传入时</div>
</slot>
4,具名插槽
子组件: <slot name="slot_name" />
父组件:
<component>
<template slot="slot_name">
内容
</template>
</component>
5,作用域插槽
子组件给父组件传值,父组件决定渲染方式时,用作用域插槽,父组件决定子组件中的元素以何种形式渲染
子组件:<slot :rainy="age"></slot>
父组件:
<component>
<template slot-scope="props" slot="slot_name">
{{ props.rainy }}
</template>
类似:
<template v-slot: [slot_name] = "props">
</template>
</component>
6,将插槽转化为可复用的模板
7,实战:插件封装、组件封装
17,动态组件
1, <component is="组件名" />
动态切换 is的值.......
<keep-alive></keep-alive> 缓存组件
2,异步组件
只有该组件需要被渲染的时候才能 触发工厂函数,且会把结果缓存起来
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
Vue.component(
'async-webpack-example',
// 这个 `import` 函数会返回一个 `Promise` 对象。
() => import('./my-async-component')
)
new Vue({
// ...
components: {
'my-component': () => import('./my-async-component')
}
})
19,自定义事件
v-on 事件监听器在 DOM 模板中会被自动转换为全小写 ,html对大小写不敏感
事件名
this.$emit("myEvent",)
<component @myEvent="" ></component>
@myEvent 自动转化为 @myevent
始终使用 kebab-case 的事件名。
20,处理边界情况
1,$root $parent $children
2, ref
<component ref="component_name"/>
this.$refs //数据传递,事件
缺点:尽量不用,并不是响应式的
3,依赖注入
provide inject
多层嵌套组件使用,勿滥用,耦合了
1, provide: 一个对象或返回一个对象的函数,该对象包含可注入起子孙的属性,可以使用ES6的Symbols作为key
2, inject { 一个字符串数组或一个对象 }
字符串数组, provide对象里哪些属性可用
一个对象
key是本地的绑定名,value是provide里对应的对象名,也可以是一个对象,
此时from属性是provide里对应的对象名,default属性是不存在时的默认值
父组件:
provide: function () {
return {
getMap: this.getMap,
message: 'hello world'
}
}
子组件:
inject: ['getMap','message']
实际上,你可以把依赖注入看作一部分“大范围有效的 prop”,除了:
祖先组件不需要知道哪些后代组件使用它提供的属性
后代组件不需要知道被注入的属性来自哪里
3,强制更新 this.$forceUpdate()
19,混入
1, 提供一种灵活的方式,分发Vue组件的可复用功能。一个混入对象可以包含任意组件选项。
当组件使用混入对象时,所有混入对象的选项将被“复合”进入改组织本身的选项
// 定义一个混入对象
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// 定义一个使用混入对象的组件
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
2,选项合并
当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。
数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
mixin Vue
1, data优先选择 Vue,覆盖mixin
2, 钩子函数:不进行合并,优先运行mixin 合并为数组
3,值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。
两个对象键名冲突时,取组件对象的键值对。
Vue.extend() 同样的规则
3,全局混入
Vue.mixin({
created: function(){
}
}) //谨慎使用
20,自定义命令
全局指令
1,Vue.directive('命令',{
inserted: function(el){
el //真实DOM
}
})
局部指令
2,directive:{
focus:{
inserted: function(){
}
}
}
3,钩子函数
bind() //初始化,仅调用一次
inserted() //被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update() //所在组件的 VNode 更新时调用
componentUpdated() //指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind() //解绑时,调用
参数:
el:指令所绑定的元素,可以用来直接操作 DOM 。
binding:一个对象,包含以下属性:
name:指令名,不包括 v- 前缀。
rawName: 指令名,包含前缀
value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
4,动态指令参数
v-pin = "200 ..."
21,渲染函数
render
1, Vue.component('anchored-heading',{
props:{
level:{
type:Number,
required: true
}
},
//动态生成标题 this.$slots.default = vnode
render: function(createElement){
return createElement('h' + this.level,this.$slots.default) // 标签名称 子节点数组
}
});
2,createElement 参数
// @returns {VNode}
createElement(
// {String | Object | Function}
// 一个 HTML 标签名、组件选项对象,或者
// resolve 了上述任何一种的一个 async 函数。必填项。
'div',
// {Object}
// 一个与模板中属性对应的数据对象。可选。
{
// (详情见下一节)
},
// {String | Array}
// 子级虚拟节点 (VNodes),由 `createElement()` 构建而成,
// 也可以使用字符串来生成“文本虚拟节点”。可选。
[
'先写一些文字',
createElement('h1', '一则头条'),
createElement(MyComponent, {
props: {
someProp: 'foobar'
}
})
]
)
this.$slots 访问静态插槽的内容,每个插槽都是一个 VNode 数组
22,插件
通常用来为Vue添加全局功能。插件的功能范围没有严格限制
1,添加全局方法或者属性。如: vue-custom-element
2,添加全局资源:指令/过滤器/过渡等。如 vue-touch
3,通过全局混入来添加一些组件选项。如 vue-router
4,添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
5,一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router
Vue.use(MyPlugin)
1,通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成:
2, 会自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件。
开发插件
1,暴露一个install方法,参数1: Vue构造器,参数2:可选的对象
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) {
// 逻辑...
}
}
23,过滤器
【注意】: 过滤的是值,是变量的值
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。
过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。
过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<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.filter('capitalize', function (value) { //value 绑定的值
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})