VUE实例
- vue实例的创建和作用
- vue实例的属性
- vue实例的方法
1. vue实例的创建和作用
new Vue({
render: (h) => h(App)
//vue在创建Vue实例时,通过调用render方法来渲染实例的DOM树,也就是这个组件渲染的是App的内容
//vue在调用render方法时,会传入一个createElement函数作为参数,也就是这里的h的实参是createElement函数,然后createElement会以App为参数进行调用
}).$mount(root) //挂载html的root节点下面
2.vue实例的属性
- $data:Vue 实例观察的数据对象。Vue 实例代理了对其 data 对象属性的访问。
- $props:当前组件接收到的 props 对象。Vue 实例代理了对其 props 对象属性的访问。
- $el: Vue实例使用的根 DOM 元素。
- $options: 用于当前 Vue 实例的初始化选项。需要在选项中包含自定义属性时会有用处:
new Vue({
customOption: 'foo',
created: function () {
console.log(this.$options.customOption) // => 'foo'
}
})
- $parent: 父实例,如果当前实例有的话。
- $root: 当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。
- $chardren: 当前实例的直接子组件。需要注意
$children
并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用$children
来进行数据绑定,考虑使用一个数组配合v-for
来生成子组件,并且使用 Array 作为真正的来源。 - $slots: 用来访问被插槽分发的内容。每个具名插槽 有其相应的属性 (例如:
v-slot:foo
中的内容将会在vm.$slots.foo
中被找到)。default
属性包括了所有没有被包含在具名插槽中的节点,或v-slot:default
的内容。 - $scopedSlots: 用来访问作用域插槽。对于包括
默认 slot
在内的每一个插槽,该对象都包含一个返回相应 VNode 的函数。vm.$scopedSlots
在使用渲染函数开发一个组件时特别有用。 - $refs: 一个对象,持有注册过
ref
特性 的所有 DOM 元素和组件实例。(帮助我们快速定位这个模板中某一个节点或者组件) - $isServer: 当前 Vue 实例是否运行于服务器。
- $attrs: 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (
class
和style
除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class
和style
除外),并且可以通过v-bind="$attrs"
传入内部组件——在创建高级别的组件时非常有用。 - $listeners: 包含了父作用域中的 (不含
.native
修饰器的)v-on
事件监听器。它可以通过v-on="$listeners"
传入内部组件——在创建更高层次的组件时非常有用。
3. vue实例的方法
方法--数据
- $watch: 观察 Vue 实例变化的一个表达式或计算属性函数。回调函数得到的参数为新值和旧值。表达式只接受监督的键路径。对于更复杂的表达式,用一个函数取代。
- $set:这是全局
Vue.set
的别名。
- $delete: 这是全局
Vue.delete
的别名。
方法-事件
- $on: 监听当前实例上的自定义事件。事件可以由
vm.$emit
触发。回调函数会接收所有传入事件触发函数的额外参数。
vm.$on('test', function (msg) {
console.log(msg)
})
vm.$emit('test', 'hi')
// => "hi"
- $once: 监听一个自定义事件,但是只触发一次,在第一次触发之后移除监听器。
- $off: 移除自定义事件监听器。
-
如果没有提供参数,则移除所有的事件监听器;
-
如果只提供了事件,则移除该事件所有的监听器;
-
如果同时提供了事件与回调,则只移除这个回调的监听器。
- $emit: 触发当前实例上的事件。附加参数都会传给监听器回调。
方法-生命周期
- $mount: 如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可用
vm.$mount()
手动地挂载一个未挂载的实例。如果没有提供elementOrSelector
参数,模板将被渲染为文档之外的的元素,并且你必须使用原生 DOM API 把它插入文档中。这个方法返回实例自身,因而可以链式调用其它实例方法。
示例:
var MyComponent = Vue.extend({
template: '<div>Hello!</div>'
})
// 创建并挂载到 #app (会替换 #app)
new MyComponent().$mount('#app')
// 同上
new MyComponent({ el: '#app' })
// 或者,在文档之外渲染并且随后挂载
var component = new MyComponent().$mount()
document.getElementById('app').appendChild(component.$el)
- $forceUpdate: 迫使 Vue 实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。(不建议使用)
- $nextTick: 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法
Vue.nextTick
一样,不同的是回调的this
自动绑定到调用它的实例上。
示例:
new Vue({
// ...
methods: {
// ...
example: function () {
// 修改数据
this.message = 'changed'
// DOM 还没有更新
this.$nextTick(function () {
// DOM 现在更新了
// `this` 绑定到当前实例
this.doSomethingElse()
})
}
}
})
- $destory: 完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。触发
beforeDestroy
和destroyed
的钩子。
Vue组件的生命周期
生命周期可以看我的另外一篇文章:Vue的生命周期
需要思考:
- 有哪些生命周期方法
- 生命周期方法的调用顺序
- 生命周期中VUE实例有哪些区别
没有暴露出来的,vue内部的渲染函数:
- render:就是render function将template编译的过程
- renderError:帮助我们调试项目,当runder function报错的时候就会执行(当前组件的render function报错才报错,不管父组件和子组件的render function报错)
new Vue({
render (h) {
throw new Error('oops')
},
renderError (h, err) {
return h('pre', { style: { color: 'red' }}, err.stack)
}
}).$mount('#app')
- errorCaptured:帮助我们收集线上的错误,如果在根组件定义了这个,然后所以的子组件报错都可以捕获到(会向上冒泡,并且正式环境可以使用)
Vue的数据绑定
class的动态绑定和style的动态绑定:vue中修改css样式和添加CSS样式
data、props、propsData、computed和watch使用场景和方法
- data
类型:Object | Function
限制:组件的定义只接受 function
。
Vue 实例的数据对象。Vue 将会递归将 data 的属性转换为 getter/setter,从而让 data 的属性能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个的 key/value 对):浏览器 API 创建的原生对象,原型上的属性会被忽略。大概来说,data 应该只能是数据 - 不推荐观察拥有状态行为的对象。
一旦观察过,不需要再次在数据对象上添加响应式属性。因此推荐在创建实例之前,就声明所有的根级响应式属性。
实例创建之后,可以通过 vm.$data
访问原始数据对象。Vue 实例也代理了 data 对象上所有的属性,因此访问 vm.a
等价于访问 vm.$data.a
。
以 _
或 $
开头的属性 不会 被 Vue 实例代理,因为它们可能和 Vue 内置的属性、API 方法冲突。你可以使用例如 vm.$data._property
的方式访问这些属性。
当一个组件被定义,data
必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data
仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data
函数,每次创建一个新实例后,我们能够调用 data
函数,从而返回初始数据的一个全新副本数据对象。
如果需要,可以通过将 vm.$data
传入 JSON.parse(JSON.stringify(...))
得到深拷贝的原始数据对象。
- props
类型:Array<string> | Object
详细:
props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。
你可以基于对象的语法使用以下选项:
type
: 可以是下列原生构造函数中的一种:String
、Number
、Boolean
、Array
、Object
、Date
、Function
、Symbol
、任何自定义构造函数、或上述内容组成的数组。会检查一个 prop 是否是给定的类型,否则抛出警告。Prop 类型的更多信息在此。default
:any
为该 prop 指定一个默认值。如果该 prop 没有被传入,则换做用这个值。对象或数组的默认值必须从一个工厂函数返回。required
:Boolean
定义该 prop 是否是必填项。在非生产环境中,如果这个值为 truthy 且该 prop 没有被传入的,则一个控制台警告将会被抛出。validator
:Function
自定义验证函数会将该 prop 的值作为唯一的参数代入。在非生产环境下,如果该函数返回一个 falsy 的值 (也就是验证失败),一个控制台警告将会被抛出。你可以在这里查阅更多 prop 验证的相关信息。
- propsData
类型:{ [key: string]: any }
限制:只用于 new
创建的实例中。
详细:
创建实例时传递 props。主要作用是方便测试。
示例:
var Comp = Vue.extend({
props: ['msg'],
template: '<div>{{ msg }}</div>'
})
var vm = new Comp({
propsData: {
msg: 'hello'
}
})
类型:{ [key: string]: Function | { get: Function, set: Function } }
详细:
计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。
注意如果你为一个计算属性使用了箭头函数,则 this
不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。
computed: {
aDouble: vm => vm.a * 2
}
计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。注意,如果某个依赖 (比如非响应式属性) 在该实例范畴之外,则计算属性是不会被更新的。
- watch
类型:{ [key: string]: string | Function | Object | Array }
详细:
一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch()
,遍历 watch 对象的每一个属性。
示例:
var vm = new Vue({
data: {
a: 1,
b: 2,
c: 3,
d: 4,
e: {
f: {
g: 5
}
}
},
watch: {
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
},
// 方法名
b: 'someMethod',
// 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
c: {
handler: function (val, oldVal) { /* ... */ },
deep: true
},
// 该回调将会在侦听开始之后被立即调用
d: {
handler: 'someMethod',
immediate: true
},
e: [
'handle1',
function handle2 (val, oldVal) { /* ... */ },
{
handler: function handle3 (val, oldVal) { /* ... */ },
/* ... */
}
],
// watch vm.e.f's value: {g: 5}
'e.f': function (val, oldVal) { /* ... */ }
}
})
vm.a = 2 // => new: 2, old: 1
deep:true对深层监听对象的每一个属性有用
Vue的原生指令
vue的指令:vue的指令
- v-text
<span v-text="msg"></span>
<!-- 和下面的一样 -->
<span>{{msg}}</span>
- v-html
更新元素的 innerHTML
。注意:内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译 。如果试图使用 v-html
组合模板,可以重新考虑是否通过使用组件来替代。
- v-show
根据表达式之真假值,切换元素的 display
CSS 属性。
当条件变化时该指令触发过渡效果。
- v-if
根据表达式的值的真假条件渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。如果元素是 <template>
,将提出它的内容作为条件块。
当条件变化时该指令触发过渡效果。
- v-else
不需要表达式
限制:前一兄弟元素必须有 v-if
或 v-else-if
。
用法:
为 v-if
或者 v-else-if
添加“else 块”。
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
- v-else-if
限制:前一兄弟元素必须有 v-if
或 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-for
预期:Array | Object | number | string | Iterable (2.6 新增)
- v-on
用法:
绑定事件监听器。事件类型由参数指定。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。
用在普通元素上时,只能监听原生 DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件。
在监听原生 DOM 事件时,方法以事件为唯一的参数。如果使用内联语句,语句可以访问一个 $event
属性:v-on:click="handle('ok', $event)"
。
从 2.4.0
开始,v-on
同样支持不带参数绑定一个事件/监听器键值对的对象。注意当使用对象语法时,是不支持任何修饰器的。
示例:
<!-- 方法处理器 -->
<button v-on:click="doThis"></button>
<!-- 动态事件 (2.6.0+) -->
<button v-on:[event]="doThis"></button>
<!-- 内联语句 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 缩写 -->
<button @click="doThis"></button>
<!-- 动态事件缩写 (2.6.0+) -->
<button @[event]="doThis"></button>
<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 阻止默认行为 -->
<button @click.prevent="doThis"></button>
<!-- 阻止默认行为,没有表达式 -->
<form @submit.prevent></form>
<!-- 串联修饰符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 键修饰符,键别名 -->
<input @keyup.enter="onEnter">
<!-- 键修饰符,键代码 -->
<input @keyup.13="onEnter">
<!-- 点击回调只会触发一次 -->
<button v-on:click.once="doThis"></button>
<!-- 对象语法 (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
- v-bind
示例:
<!-- 绑定一个属性 -->
<img v-bind:src="imageSrc">
<!-- 动态特性名 (2.6.0+) -->
<button v-bind:[key]="value"></button>
<!-- 缩写 -->
<img :src="imageSrc">
<!-- 动态特性名缩写 (2.6.0+) -->
<button :[key]="value"></button>
<!-- 内联字符串拼接 -->
<img :src="'/path/to/images/' + fileName">
<!-- class 绑定 -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]">
<!-- style 绑定 -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>
<!-- 绑定一个有属性的对象 -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
<!-- 通过 prop 修饰符绑定 DOM 属性 -->
<div v-bind:text-content.prop="text"></div>
<!-- prop 绑定。“prop”必须在 my-component 中声明。-->
<my-component :prop="someThing"></my-component>
<!-- 通过 $props 将父组件的 props 一起传给子组件 -->
<child-component v-bind="$props"></child-component>
<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>
- v-model
- v-slot
- v-pre
- v-cloak
- v-once
Vue的组件之组件的定义
定义全局组件:
使用index.js将全部需要全局定义的组件引入:
示例代码:
/*所有的自定义全局组件在此注册*/
import Vue from 'vue'
function registerEachComponent(item) {
Vue.component(item.name,item.component);
}
function registerComponents(components) {
components.map((item)=>{
registerEachComponent(item)
})
}
let components = [
{
name: 'common-layout',
component: resolve => require(['./common-layout/common-layout.vue'], resolve)
},
{
name: 'common-section',
component: resolve => require(['./common-section/index.vue'], resolve)
},
{
name: 'commonInquire',
component: resolve => require(['./commonInquire/index.vue'], resolve)
},
{
name: 'CommonTable',
component: resolve => require(['./commonTable/index.vue'], resolve)
},
];
registerComponents(components);
在main.js中引入:
/*引入全局注册的组件*/
import './components/global/index.js'
局部组件:
将定义的组件在需要使用的地方引入并通过components定义
组件定义配置:
- props:不应该主动修改props的内容,
- emit:子组件通过emit来让父组件监听子组件的事件
Vue的组件之组件的继承
extends:将一个能在多个项目中使用的组件通过extends来实现继承,通过覆盖和新增新功能实现对原有组件的使用和拓展
示例:
// 假设component是通用的组件
const component2 = {
extends: component,
data () {
text: 1
},
mounted () {
console.log('comp2 mounted')
}
}
注意:如果父组件在mounted定义了事件,然后你在子组件也定义了事件,这样会是父组件的事件先触发,子组件的事件后触发
parent:通过parent可以查看父组件的一些属性和方法(不建议通过parent修改父组件的属性值和方法)
Vue的组件之自定义双向绑定
使用v-model来实现组件的自定义双向绑定
1.通过在子组件中的props得到值,然后将新的值emit出去,这就实现了双向绑定
2.在内部组件使用model
model: {
prop: 'value1',
event: 'change'
},
props: ['value1']
参考文章:Vue父子组件如何双向绑定传值
Vue的组件之高级属性
slot
定义组件compOne:
<div>
<div class="header">
<slot name="header"></slot>
</div>
<div>
<slot name="body"></slot>
</div>
</div>
使用:
<comp-one>
<span slot="header">this is header</span>
<span slot="body">this is body</span>
</comp-one>
文档:v-slot
slot-scope
使用组件中的属性
定义:
<div>
<slot value="456" aaa="111"></slot>
</div>
使用:
<comp-one>
<span slot-scope="props">{{props.value}}{{props.aaa}}</span>
</comp-one>
注意:ref用在组件和原生标签上的区别,在组件上是指向VueCompone,在原生标签上是一个html节点
provide和inject的使用
Vue.js 不建议在业务中使用这对 API,而是在插件 / 组件库
假设有两个组件: A.vue 和 B.vue,B 是 A 的子组件。
// A.vue
export default {
provide: {
name: 'Aresn'
}
}
// B.vue
export default {
inject: ['name'],
mounted () {
console.log(this.name); // Aresn
}
}
可以看到,在 A.vue 里,我们设置了一个 provide: name,值为 Aresn,它的作用就是将 name 这个变量提供给它的所有子组件。而在 B.vue 中,通过 inject
注入了从 A 组件中提供的 name 变量,那么在组件 B 中,就可以直接通过 this.name 访问这个变量了,它的值也是 Aresn。这就是 provide / inject API 最核心的用法。
只要一个组件使用了 provide
向下提供数据,那其下所有的子组件都可以通过 inject
来注入,不管中间隔了多少代,而且可以注入多个来自不同父级提供的数据。需要注意的是,一旦注入了某个数据,比如上面示例中的 app
,那这个组件中就不能再声明 app
这个数据了,因为它已经被父级占有。
Vue的组件之render function
<comp-one ref="comp">
<span ref="span">
{{value}}
</span>
</comp-one>
上面的代码通过render函数来实现:
render (createElement) {
return createElement('comp-one',{
ref: 'comp'
},[
createElement('span', {
ref: 'span
},this.value)
])
}
vue将template编译成一个render,形成一个虚拟的DOM
文档:JSX