구성 요소
구성 요소는 HTML 요소를 확장하고 재사용 가능한 코드를 캡슐화할 수 있으며, vue.js의 컴파일러는 일부 경우에 구성 요소에 특수 기능을 추가할 수 있습니다. 또한 is 속성으로 확장된 기본 HTML 요소의 형태여야 합니다.
Vue.js 구성 요소는 사전 정의된 동작을 갖춘 ViewModel 클래스로 이해될 수 있습니다. 구성 요소는 많은 옵션을 미리 정의할 수 있지만 핵심 옵션은 다음과 같습니다.
템플릿(템플릿): 템플릿은 최종적으로 사용자에게 표시되는 데이터와 DOM 간의 매핑 관계를 선언합니다.
초기 데이터(data): 컴포넌트의 초기 데이터 상태입니다. 재사용 가능한 구성 요소의 경우 일반적으로 비공개 상태입니다.
외부 매개변수(props) 허용: 매개변수를 통해 구성요소 간에 데이터가 전송되고 공유됩니다. 매개변수는 기본적으로 단방향(하향식)으로 바인딩되지만 양방향으로 명시적으로 선언할 수도 있습니다.
메서드: 데이터에 대한 수정 작업은 일반적으로 구성 요소의 메서드 내에서 수행됩니다. 사용자 입력 이벤트 및 구성 요소 메서드는 v-on 지시문을 통해 바인딩될 수 있습니다.
수명 주기 후크: 구성 요소는 생성, 연결, 삭제 등과 같은 여러 수명 주기 후크 기능을 트리거합니다. 이러한 후크 함수에서는 일부 사용자 정의 논리를 캡슐화할 수 있습니다. 기존 MVC와 비교하면 컨트롤러의 로직이 이러한 후크 기능으로 분산되어 있다는 것을 이해할 수 있습니다.
전용 리소스(자산): Vue.js에서는 사용자가 정의한 명령어, 필터, 구성 요소 등을 총칭하여 리소스라고 합니다. 전역적으로 등록된 리소스는 쉽게 이름 충돌을 일으킬 수 있으므로 구성 요소는 자체 개인 리소스를 선언할 수 있습니다. 개인 리소스는 구성 요소와 해당 하위 구성 요소에 의해서만 호출될 수 있습니다.
또한 동일한 구성 요소 트리 내의 구성 요소는 내장된 이벤트 API를 통해 통신할 수도 있습니다. Vue.js는 구성 요소 정의, 재사용 및 중첩을 위한 완전한 API를 제공하므로 개발자는 구성 요소를 사용하여 빌딩 블록과 같은 전체 애플리케이션 인터페이스를 구축할 수 있습니다.
구성 요소는 코드의 효율성, 유지 관리성 및 재사용성을 크게 향상시킵니다.
컴포넌트를 사용하여 등록
1. 컴포넌트 생성자 생성:
var MyComponent = Vue.extend({ //选项 })
2 . 생성자를 구성 요소로 사용하고 Vue.comComponent(tag,constructor)에 등록합니다:
Vue.component('my-component',MyComponent)
3. , 자체적으로 사용하십시오.
<div id = "example"> <my-component></my-component> </div>
예:
<div id="example"> <my-component></my-component> </div> // 定义 var MyComponent = Vue.extend({ template: '<div>A custom component!</div>' }) // 注册 Vue.component('my-component', MyComponent) // 创建根实例 new Vue({ el: '#example' })
은 다음과 같이 렌더링됩니다.
<div id = "example"> <div>A custom component!</div> </div>
구성 요소의 템플릿은 사용자 정의 요소를 대체합니다. 장착 지점으로. 교체 여부를 결정하려면 인스턴스 옵션 교체를 사용할 수 있습니다.
로컬 등록
인스턴스 옵션 컴포넌트로 등록합니다. 각 컴포넌트를 전역적으로 등록할 필요는 없습니다.
var Child = Vue.extend({ /* ... */ }) var Parent = Vue.extend({ template: '...', components: { // <my-component> 只能用在父组件模板内 'my-component': Child } })
이 캡슐화는 지시어, 필터, 전환과 같은 다른 리소스에도 적용됩니다.
등록 구문 설탕
// 在一个步骤中扩展与注册 Vue.component('my-component', { template: '<div>A custom component!</div>' }) // 局部注册也可以这么做 var Parent = Vue.extend({ components: { 'my-component': { template: '<div>A custom component!</div>' } } })
구성 요소 옵션 문제
Vue 생성자에 전달된 대부분의 옵션은 또한 Vue.extend()에서는 data와 el 외에도 단순히 객체를 data 옵션으로 Vue.extend()에 전달하면 모든 인스턴스가 동일한 데이터 객체를 공유하므로 함수를 data 옵션을 선택하면 이 함수가 새 개체를 반환하도록 합니다.
var MyComponent = Vue.extend({ data: function () { return { a: 1 } } })
템플릿 구문 분석
Vue의 템플릿은 다음을 사용하는 DOM 템플릿입니다. 브라우저의 기본 템플릿 파서이므로 유효한 HTML 조각이어야 합니다. 일부 HTML 요소에는 내부에 배치할 수 있는 요소에 대한 제한이 있습니다.
a는 다른 대화형 요소(예: 버튼, 링크)를 포함할 수 없습니다. )
ul 및 ol은 li만 직접 포함할 수 있습니다.
select는 option과 optgroup만 포함할 수 있습니다.
table은 thead, tbody, tfoot, tr, caption, col만 직접 포함할 수 있습니다. , colgroup
tr은 th와 td만 직접 포함할 수 있습니다
실제로 이러한 제한으로 인해 예상치 못한 결과가 발생할 수 있습니다. 간단한 경우에는 작동할 수 있지만 브라우저가 유효성을 검사하기 전에는 사용자 정의 구성 요소의 확장 결과에 의존할 수 없습니다. 예를 들어
750d7c37f87c44b67b1e945084b6bc455a07473c87748fb1bf73f23d45547ab8...4afa15d3069109ac30911f04c56f3338c3b6035d40e49dd3cf5dfe627a1d2a00는 my-select 구성 요소가 결국 다음으로 확장되더라도 유효한 템플릿이 아닙니다. 1255615300cfad2071603556f8adc136..a33854621d9ed860371434114a7b4cae.
또 다른 결과는 맞춤 태그(3f29937d4ced0eda173ecfb4386e9662, d477f9ce7bf77f53fbcf36bec1b69b7a, ec872302d9f7ec49547f9998f4be2186와 같은 맞춤 요소 및 특수 태그 포함)를 ul, select, table 등 내에서 사용할 수 없다는 것입니다. 제한된 태그 내에 있습니다. 이러한 요소 내부에 배치된 맞춤 태그는 요소 외부로 들어올려져 잘못 렌더링됩니다.
커스텀 요소의 경우 is 속성을 사용해야 합니다:
f5d188ed2c074f8b944552db028f98a1
<tr is="my-component"></tr> </table> //<template> 不能用在 <table> 内,这时应使用 <tbody>,<table> 可以有多个 <tbody> <table> <tbody v-for="item in items"> <tr>Even row</tr> <tr>Odd row</tr> </tbody> </table>
Props
props를 사용하여 데이터 전달
props를 사용하여 하위 구성 요소에 배열을 전달할 수 있습니다. 상위 구성 요소에서 하위 구성 요소로 전달하려면 props 옵션(
Vue.component('child', { // 声明 props props: ['msg'], // prop 可以用在模板内 // 可以用 `this.msg` 设置 template: '<span>{{ msg }}</span>' })
)을 사용하여 명시적으로 prop을 선언해야 합니다. 문자열:
<child msg="hello!"></child>
동적 소품
用v-bind绑定动态props到父组件的数据,每当父组件的数据变化时,也会传导给子组件:
<div> <input v-model="parentMsg"> <child v-bind:my-message="parentMsg"></child> //<child :my-message="parentMsg"></child> </div>
props绑定类型
prop默认是单向绑定,当父组件的属性变化时,将传导给子组件,但是反过来不会,这是为了防止子组件无意修改了父组件的状态,可以使用.sync或.once绑定修饰符显式地强制双向或单次绑定:
<!-- 默认为单向绑定 --> <child :msg="parentMsg"></child> <!-- 双向绑定 --> <child :msg.sync="parentMsg"></child> <!-- 单次绑定 --> <child :msg.once="parentMsg"></child>
如果 prop 是一个对象或数组,是按引用传递。在子组件内修改它会影响父组件的状态,不管是使用哪种绑定类型。
父子组件通信
父链
子组件可以用this.$parent访问它的父组件,根实例的后代可以用this.$root访问它,父组件有一个数组this.$children,包含它所有的子元素
自定义事件
Vue实例实现了一个自定义事件接口,用于在组件树中通信,这个事件系统独立于原生DOM事件,用法也不同,每一个Vue实例都是一个事件触发器:
使用 $on() 监听事件;
使用 $emit() 在它上面触发事件;
使用 $dispatch() 派发事件,事件沿着父链冒泡;
使用 $broadcast() 广播事件,事件向下传导给所有的后代。
不同于 DOM 事件,Vue 事件在冒泡过程中第一次触发回调之后自动停止冒泡,除非回调明确返回 true。
<!-- 子组件模板 --> <template id="child-template"> <input v-model="msg"> <button v-on:click="notify">Dispatch Event</button> </template> <!-- 父组件模板 --> <div id="events-example"> <p>Messages: {{ messages | json }}</p> <child></child> </div> // 注册子组件 // 将当前消息派发出去 Vue.component('child', { template: '#child-template', data: function () { return { msg: 'hello' } }, methods: { notify: function () { if (this.msg.trim()) { this.$dispatch('child-msg', this.msg) this.msg = '' } } } }) // 初始化父组件 // 将收到消息时将事件推入一个数组 var parent = new Vue({ el: '#events-example', data: { messages: [] }, // 在创建实例时 `events` 选项简单地调用 `$on` events: { 'child-msg': function (msg) { // 事件回调内的 `this` 自动绑定到注册它的实例上 this.messages.push(msg) } } })
效果:
使用v-on绑定自定义事件
在模板中子组件用到的地方声明事件处理器,为此子组件可以用v-on监听自定义事件:
4084e2349312ebcd04e4de37381def6c7d4dd9c7239aac360e401efe89cbb393
当子组件触发了 "child-msg" 事件,父组件的 handleIt 方法将被调用。所有影响父组件状态的代码放到父组件的 handleIt 方法中;子组件只关注触发事件。
子组件索引
使用v-ref为子组件指定一个索引ID,可以直接访问子组件
<div id="parent"> <user-profile v-ref:profile></user-profile> </div> var parent = new Vue({ el: '#parent' }) // 访问子组件 var child = parent.$refs.profile
使用Slot分发内容
内容分发:混合父组件的内容与子组件自己的模板的方式,使用特殊的58cb293b8600657fad49ec2c8d37b472元素作为原始内容的插槽。
编译作用域
父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
绑定子组件内的指令到一个组件的根节点:
Vue.component('child-component', { // 有效,因为是在正确的作用域内 template: '<div v-show="someChildProperty">Child</div>', data: function () { return { someChildProperty: true } } })
类似地,分发内容是在父组件作用域内编译。
单个slot
父组件的内容将被抛弃,除非子组件模板包含58cb293b8600657fad49ec2c8d37b472,如果子组件模板只有一个没有特性的slot,父组件的整个内容将插到slot所在的地方并替换它。
58cb293b8600657fad49ec2c8d37b472 标签的内容视为回退内容。回退内容在子组件的作用域内编译,当宿主元素为空并且没有内容供插入时显示这个回退内容。
假定 my-component 组件有下面模板:
<div> <h1>This is my component!</h1> <slot>
如果没有分发内容则显示我。
</slot> </div>
父组件模板:
<my-component> <p>This is some original content</p> <p>This is some more original content</p> </my-component>
渲染结果:
<div> <h1>This is my component!</h1> <p>This is some original content</p> <p>This is some more original content</p> </div>
具名slot
58cb293b8600657fad49ec2c8d37b472元素可以用一个特殊特性name配置如何分发内容,多个slot可以有不同的名字,具名slot将匹配内容片段中有对应slot特性的元素。
仍然可以有一个匿名 slot,它是默认 slot,作为找不到匹配的内容片段的回退插槽。如果没有默认的 slot,这些找不到匹配的内容片段将被抛弃。
动态组件
多个组件可以使用同一个挂载点,然后动态地在它们之间切换,使用保留的8c05085041e56efcb85463966dd1cb7e元素,动态地绑定到它的is特性:
new Vue({ el: 'body', data: { currentView: 'home' }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } }) <component :is="currentView"> <!-- 组件在 vm.currentview 变化时改变 --> </component> keep-alive
把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。
39a981128a40da37853cce84bffb2ba2
b2b0822175891cddec63f9cdd3f18ba9
2724ec0ed5bf474563ac7616c8d7a3cd
activate钩子
控制组件切换时长,activate 钩子只作用于动态组件切换或静态组件初始化渲染的过程中,不作用于使用实例方法手工插入的过程中。
Vue.component('activate-example', { activate: function (done) { var self = this loadDataAsync(function (data) { self.someData = data done() }) } })
transition-mode
transition-mode 特性用于指定两个动态组件之间如何过渡。
在默认情况下,进入与离开平滑地过渡。这个特性可以指定另外两种模式:
in-out:新组件先过渡进入,等它的过渡完成之后当前组件过渡出去。
out-in:当前组件先过渡出去,等它的过渡完成之后新组件过渡进入。
示例:
<!-- 先淡出再淡入 --> <component :is="view" transition="fade" transition-mode="out-in"> </component> .fade-transition { transition: opacity .3s ease; } .fade-enter, .fade-leave { opacity: 0; }
Vue.js 组件 API 来自三部分——prop,事件和 slot:
prop 允许外部环境传递数据给组件;
事件 允许组件触发外部环境的 action;
슬롯을 사용하면 외부 환경에서 구성 요소의 뷰 구조에 콘텐츠를 삽입할 수 있습니다.