>  기사  >  웹 프론트엔드  >  Vue.js 구성 요소 및 구성 요소 통신에 대한 심층 분석

Vue.js 구성 요소 및 구성 요소 통신에 대한 심층 분석

高洛峰
高洛峰원래의
2017-01-16 12:39:241709검색

기본적으로 공식 웹사이트의 가이드에 따라 모든 것을 정리했습니다: http://vuejs.org/guide/index.html 여기에서는 관련된 모든 항목을 하나로 묶는 Todo List 애플리케이션을 예로 들어 보겠습니다. 기사 코드는 모두 github에 있습니다 https://github.com/lihongxun945/vue-todolist

Vue 인스턴스

Vue 애플리케이션은 루트 vue 인스턴스에 의해 부팅되고 시작됩니다. Vue 인스턴스는 다음과 같이 생성됩니다.

var vm = new Vue({
 // options
})

인스턴스는 실제로 MVVM의 VM입니다. 전달된 구성 객체의 데이터에 있는 모든 속성은 이름 충돌을 피하기 위해 인스턴스에 마운트됩니다. Vue의 내장 메소드는 $로 시작하는 속성을 인스턴스에 마운트합니다.

인스턴스는 생성부터 소멸까지 다음과 같은 수명 주기를 거칩니다.

초기화 중 대략 세 단계를 거칩니다.
• 바인딩 데이터 모니터링, 즉 데이터 모니터링
• 템플릿 컴파일
• 문서 삽입 또는 해당 DOM 바꾸기
# Vue 기본 구문

데이터 바인딩

Vue는 마스타셰와 유사한 구문을 사용합니다. 일반적으로 사용되는 바인딩 구문은 다음 범주로 구분됩니다.
• {{ data }} {{ data | filter}}
와 같은 mastache 구문 • v-bind: href와 같은 v-bind 바인딩 속성 v-bind :class
•v-on:click, v-on:submit

여기서 v-*는 지시어입니다

예:

19de9f32bc61168916c704eb219bf5b9

속성 계산

Vue는 흥미로운 속성 계산을 지원합니다. 구문, 다른 속성에서 계산할 속성을 지정할 수 있으므로 이를 달성하기 위해 $watch를 사용할 필요가 없습니다.

var vm = new Vue({
 el: '#example',
 data: {
 a: 1
 },
 computed: {
 // a computed getter
 b: function () {
 // `this` points to the vm instance
 return this.a + 1
 }
 }
})

## 흐름 제어 및 목록 관련 구문 `v-if`, `v-show`, `v-else`, `v-for` 포함


양식

양방향 데이터 바인딩:


04815cf4782a373a364d283dc13af234

b3f1ed7539c63a96e9c626bfdb87e9c3


## 애니메이션 애니메이션은 클래스 추가 및 삭제 방식으로 Angular, React와 동일하게 구현됩니다. # Component


Component의 기본 사용법

Component의 정의는 두 부분으로 구성됩니다.

1 구성 요소 클래스 생성:

var Profile = Vue.extend({
 template: "<div> Lily </div>"
});

2 태그 이름 등록:


Vue.comComponent("me-profile", Profile);

이 방법으로 태그 이름을 통해 이러한 구성 요소를 사용할 수 있습니다.

<div id="todo">
 <my-profile></my-profile>
 <form v-on:submit="add" v-on:submit.prevent>
 <input type="text" v-model="input"/>
 <input type="submit" value=&#39;add&#39; />
 </form>
 ...
</div>

Vue.comComponent("me-profile", Profile)는 전역 등록입니다. 특정 페이지에서만 사용되는 경우 로컬에서 등록할 수 있습니다:

var vm = new Vue({
 el: "#todo",
 components: {
 "my-profile": Profile
 },
 ...
}

Vue 인스턴스는 todo 요소에 바인딩되어 있으므로 my-profile이 이 요소 외부에 배치된 경우에만 Vue 인스턴스에 의해 초기화됩니다.

참고:


Vue 생성자에 전달할 수 있는 매개변수는 기본적으로 Vue.extend에서 사용할 수 있지만 el과 data 두 매개변수에 주의해야 합니다. 다른 인스턴스를 피하기 위해 동일한 객체를 공유할 때 항상 함수를 통해 새 객체를 반환하는 것이 더 안정적입니다:

var MyComponent = Vue.extend({
 data: function () {
 return { a: 1 }
 }
})

매개변수가 동일하기 때문에 실제로는 동일합니다. 하지만 하나는 구성 요소이고 하나는 Vue를 시작하도록 안내하는 데 사용됩니다.

템플릿 참고사항

Vue는 기본 DOM이므로 일부 사용자 정의 태그는 DOM 표준을 준수하지 않을 수 있습니다. 예를 들어 테이블에서 tr을 사용자 정의하려는 경우 my- 컴포넌트 직접, 아니오 사양을 준수하므로 다음과 같이 작성해야 합니다:

<table>
 <tr is="my-component"></tr>
</table>

Props 전송 데이터

Vue에서는 각 컴포넌트가 독립적이므로 상위 클래스 데이터에 직접 액세스하면 안 됩니다. 그럼 props를 통해 하위 컴포넌트에 데이터를 전달하는데, React와 비슷한가요?

React와 달리 Vue의 하위 구성 요소는 먼저 자체 props를 선언해야 합니다.

var Profile = Vue.extend({
 props: ["name"],
 template: `
 <h2>{{name}}&#39;s Todo List</h2>
 <h4>{{name}} is a good girl</h4>
 `
});

그런 다음 Profile을 사용할 때 다음과 같은 매개 변수를 전달할 수 있습니다.

< ;my-profile name='Lily'>2ce8caae7ced446f67526b3e9d39dfa1

이 메서드는 리터럴을 통해 매개변수를 전달하므로 전달되는 값은 문자열이어야 합니다. 또 다른 방법은 v-bind를 통해 매개변수를 동적으로 전달하는 것입니다. 이는 데이터를 양방향으로 바인딩하거나 문자열이 아닌 매개변수를 전달할 수 있습니다.

1bb17a1f1b55d117ee6295fdbd893613b9c68978612d2bb2405a5ce3e24e00ae

v-bind 문자열인 경우 상위 컴포넌트의 데이터에 있는 해당 필드에 바인딩됩니다. 예를 들어 위는 입력값의 양방향 바인딩입니다. 숫자인 경우 숫자에 바인딩됩니다.

Vue는 단방향 또는 양방향 데이터 바인딩을 명시적으로 지정할 수도 있습니다.

<!-- default, one-way-down binding -->
<child :msg="parentMsg"></child>
 
<!-- explicit two-way binding -->
<child :msg.sync="parentMsg"></child>
 
<!-- explicit one-time binding -->
<child :msg.once="parentMsg"></child>

Props 확인

좋은 구성 요소는 항상 먼저 다음과 같은지 확인해야 합니다. 또한 일부 매개변수의 기본값을 설정해야 할 수도 있습니다.

var Profile = Vue.extend({
 input: {
 type: String
 }
});

상위-하위 구성요소 통신

上面讲到的 props 其实就是父组件向子组件传递消息的一种方式。 
在子组件中有一个 this.$parent 和 this.$root 可以用来方法父组件和根实例。不过,现在我们应该避免这么做。因为组件本身就是为了封装独立的逻辑,如果又去直接访问父组件的数据就破坏了组件的封装性。 
所以我们应该还是应该通过父组件向子组件传递 props 的方式来通信。

当然 props 其实只能做回调。在 React 中就探讨过这个问题,React 的做法就是通过 props 来做,传一个回调函数给子组件。其实我不是很喜欢这种把回调函数传来传去的方式,我更喜欢的是事件的方式。Vue 中子组件可以通过通过事件和父组件进行通信的。向父组件发消息是通过 this.$dispatch,而向子组件发送消息是通过 this.$boardcast,这里都是向所有的父亲和孩子发送消息,但是一旦执行一个回调之后就会停止,除非这个回调函数显式返回了 true。

我们把之前的Todo List拆成不同的组件来实现,这样可以体验下如何进行组件的双向通信,我们拆分出两个组件,分别是 List 和 Form 。

Form 负责处理用户输入,并在提交表单的时候向父组件发送一个 add 消息,代码如下:

var Form = Vue.extend({
 props: {
 username: {
 type: String,
 default: "Unnamed"
 }
 },
 data: function() {
 return {
 input: "",
 };
 },
 template: `
 <h1>{{username}}&#39;s Todo List</h1>
 <form v-on:submit="add" v-on:submit.prevent>
 <input type="text" v-model="input"/>
 <input type="submit" value=&#39;add&#39; />
 </form>
 `,
 methods: {
 add: function() {
 this.$dispatch("add", this.input); //这里就是向父组件发送消息
 this.input = "";
 }
 }
});

 List 只负责展示列表和处理用户勾选操作,它接收到 add 消息之后会在自己上添加一个条目:

var List = Vue.extend({
 template: `
 <ul>
 <li v-for=&#39;todo in list&#39;>
 <label v-bind:class="{ done : todo.done }" >
  <input type="checkbox" v-model="todo.done"/>
  {{todo.title}}
 </label>
 </li>
 </ul>`,
 props: {
 initList: {
 type: Array
 }
 },
 data: function() {
 return {
 list: []
 }
 },
 events: {
 add: function(input) {
 if(!input) return false;
 this.list.unshift({
 title: input,
 done: false
 });
 }
 }
});

 然后,因为这是两个组件,当然需要一个 Vue 实例来引导启动,我们的实例如下:

var vm = new Vue({
 el: "#todo",
 components: {
 "todo-form": Form,
 "todo-list": List
 },
 events: {
 add: function(input) {
 this.$broadcast("add", input);
 }
 }
});

 注意,其实 Form 和 List 在逻辑上是平级的组件,所以他们没有父子关系,他们共同都是 vm 的孩子。这里 vm 接到 Form 的消息之后会转发给 List。

html 代码就更简单了:

<div id="todo">
<todo-form username=&#39;Lily&#39;></todo-form>
<todo-list></todo-list>
</div>

 Slot

通过 Slot 可以实现把父组件渲染出来的HTML插入到子组件中,目前还不清楚什么时候会需要这样做,而且这么做对子组件的侵入性太大。

动态切换组件

这个功能感觉有点多余,感觉很多情况下我们应该是通过逻辑代码来实现切换,而不是通过Vue内置的动态组件来切换。不过用来实现一个类似 tab 切换的功能还是很方便的。

我们这里给 Todo List 增加一个 about 页面。那么首先我们需要把 vm 改成一个组件,这个组件叫 Todo,它就是整个 Todo 页面:

var Todo = Vue.extend({
 template: `
 <div id="todo">
 <todo-form username=&#39;Lily&#39;></todo-form>
 <todo-list></todo-list>
 <slot>not show</slot>
 </div>
 `,
 components: {
 "todo-form": Form,
 "todo-list": List
 },
 events: {
 add: function(input) {
 this.$broadcast("add", input);
 }
 }
});

 

 其实改动就第一行。

然后我们需要创建一个 About 组件:

var About = Vue.extend({
 template: `
 <div id="about">
 <p>About Todo List V0.1.0</p>
 <p>Content here</p>
 </div>`
});

 接下来是重点了,我们要创建一个实例 vm,这vm要负责切换这两个页面:

var vm = new Vue({
 el: "body",
 data: {
 currentView: "todo"
 },
 components: {
 "todo": Todo,
 "about": About
 }
});

 这里我们定义了一个 currentView 字段,当然可以是任意名称,然后通过特殊的 component 标签来进行组件切换:

<component :is="currentView"></component>
 <ul>
 <li><label><input type="radio" name=&#39;page&#39; value=&#39;todo&#39; v-model=&#39;currentView&#39;> Home</label></li>
 <li><label><input type="radio" name=&#39;page&#39; value=&#39;about&#39; v-model=&#39;currentView&#39;> About</label></li>
 </ul>

 上面的代码有两处需要注意:
 •通过 component这个特殊标签,然后用 :is 属性来进行组件的切换。
 •radio 通过双向绑定来修改 currentView 字段,从而实现点击之后就可以进行切换。

数据绑定的实现原理

Vue 把双向绑定称作 reactive,可以翻译为响应式数据绑定。内部是通过 ES5 定义的 getter 和 setter 方法实现的,所以不支持 IE8 及以下浏览器,这种实现方式有两个容易犯错的地方:
 •如果在 data 上直接添加和删除属性是无法被检测到的,一般删除是不会的,但是可能会动态添加,这个时候应该通过 vm.$set(“name”, value) 的方式来添加。
 •无法检测到对象内部的变化,也就是只能检测 data 的属性变化,如果 data.a 是一个对象,那么 data.a.b = 1 这种变化是无法被检测到的。这种情况下应该创建一个新的对象并赋值给 data.a 就行了。 

异步更新机制

Vue 对DOM的更新是异步的! 这个异步是在一个异步队列中进行的,不过这个异步队列会在当前的 Event Loop 中执行完,所以如果修改了 Data 立刻去DOM中做查询操作是不对的,这个时候DOM还没有更新,正确的做法是这样做:

vm.msg = &#39;new message&#39; // change data
vm.$el.textContent === &#39;new message&#39; // false
Vue.nextTick(function () {
 vm.$el.textContent === &#39;new message&#39; // true
})

 或者这样:

vm.$nextTick(function () {
 this.$el.textContent === &#39;new message&#39; // true
})

 花了半天时间才看完组件,下面应该去看一下另一个重点: Directive

本文已被整理到了《Vue.js前端组件学习教程》,欢迎大家学习阅读。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持PHP中文网。

更多X深入探讨Vue.js组件和组件通信相关文章请关注PHP中文网!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.