Vue 슬롯 실현 원리

13579 단어 Vue소켓
샘플 코드

<!--    comA -->
<template>
  <div class='demo'>
    <slot><slot>
    <slot name='test'></slot>
    <slot name='scopedSlots' test='demo'></slot>
  </div>
</template>
<!--     -->
<comA>
  <span>      </span>
  <template slot='test'>      </template>
  <template slot='scopedSlots' slot-scope='scope'>       (  ){{scope.test}}</template>
  <template v-slot:scopedSlots='scopeProps' slot-scope='scope'>       (  ){{scopeProps.test}}</template>
</comA>
2.현상 을 통 해 본질 을 본다.
슬롯 의 역할 은 내용 의 분 배 를 실현 하고 내용 의 분 배 를 실현 하 는 것 이 며 두 가지 조건 이 필요 하 다.
  • 자리 차지 문자
  • 배포 내용
  • 구성 요소 내부 에서 정 의 된 slot 탭 은 자리 표시 자,부모 구성 요소 에 있 는 슬롯 내용 으로 이해 할 수 있 습 니 다.바로 배포 할 내용 입 니 다.슬롯 처리 의 본질은 지 정 된 내용 을 지 정 된 위치 에 두 는 것 이다.쓸데없는 말 은 많이 하지 않 고 이 글 에서 알 수 있 을 것 이다.
  • 슬롯 의 실현 원리
  • render 방법 중 플러그 를 어떻게 사용 합 니까
  • 3.실현 원리vue 구성 요소 의 예화 순 서 는 부모 구성 요소 상태 초기 화(data,computed,watch..)->템 플 릿 컴 파일->생 성 render 방법->예화 렌 더 링 watcher->render 방법 을 호출 하여 VNode->patch VNode 을 생 성 합 니 다.실제 DOM 으로 변환->인 스 턴 스 화 서브 구성 요소-->...같은 절 차 를 반복 합 니 다->하위 구성 요소 가 생 성 한 진실 DOM 을 부모 구성 요소 가 생 성 한 진실 DOM 에 마 운 트 하고 페이지 에 마 운 트 합 니 다->이전 노드 제거
    상기 절차 에서 추측 할 수 있다.
    1.부모 구성 요소 템 플 릿 은 하위 구성 요소 이전에 해석 되 기 때문에 부모 구성 요 소 는 먼저 슬롯 템 플 릿 내용 을 가 져 옵 니 다.
    2.하위 구성 요소 템 플 릿 을 분석 한 후에 하위 구성 요소 가 render 방법 으로 VNode 을 생 성 할 때 일부 수단 을 통 해 슬롯 의 VNode 노드 를 얻 을 수 있 습 니 다.
    3.역할 영역 슬롯 은 하위 구성 요소 내 변 수 를 가 져 올 수 있 기 때문에 역할 영역 슬롯 의 VNode 생 성 은 동적 입 니 다.즉,실시 간 으로 하위 구성 요소 에 들 어 가 는 역할 영역 scope 이 필요 합 니 다.
    전체 슬롯 의 처리 단 계 는 크게 세 단계 로 나 뉜 다.
  • 컴 파일
  • 렌 더 링 템 플 릿 생 성
  • 생 성 VNode
  • 아래 코드 를 예 로 들 면 플러그 가 돌아 가 는 과정 을 간략하게 요약 한다.
    
    <div id='app'>
      <test>
        <template slot="hello">
          123
        </template>
      </test>
    </div>
    <script>
      new Vue({
        el: '#app',
        components: {
          test: {
            template: '<h1>' +
              '<slot name="hello"></slot>' +
              '</h1>'
          }
        }
      })
    </script>
    4.부모 구성 요소 컴 파일 단계
    컴 파일 은 템 플 릿 파일 을 AST 문법 트 리 로 해석 하고 슬롯 template 을 다음 과 같은 데이터 구조 로 해석 합 니 다.
    
    {
      tag: 'test',
      scopedSlots: { //      
        // slotName: ASTNode,
        // ...
      }
      children: [
        {
          tag: 'template',
          // ...
          parent: parentASTNode,
          children: [ childASTNode ], //        ,     123
          slotScope: undefined, //         
          slotTarget: "\"hello\"", //       
          slotTargetDynamic: false //          
          // ...
        }
      ]
    }
    5.부모 구성 요소 생 성 렌 더 링 방법AST 문법 트 리 에 따라 렌 더 링 방법 문자열 을 분석 한 결과 부모 구성 요소 가 생 성 된 결 과 는 다음 과 같다.이 구 조 는 우리 가 직접 쓴 render 방법 과 일치 하고 본질 은 모두 VNode 을 생 성 하 는 것 이 며 _c 또는 hthis.$createElement 의 줄 임 말 에 불과 하 다.
    
    with(this){
      return _c('div',{attrs:{"id":"app"}},
      [_c('test',
        [
          _c('template',{slot:"hello"},[_v("
    123
    ")])],2) ], 1) }
    6.부모 구성 요소 생 성 VNoderender 방법 을 호출 하여 VNode 을 생 성 하고 VNode 의 구체 적 인 형식 은 다음 과 같다.
    
    {
      tag: 'div',
      parent: undefined,
      data: { //   VNode   
        attrs: { id: '#app' }
      },
      context: componentContext, //      
      elm: undefined, //   DOM  
      children: [
        {
          tag: 'vue-component-1-test',
          children: undefined, //            ,             
          parent: undefined,
          componentOptions: { //      
            Ctor: VueComponentCtor, //       
            data: {
              hook: {
                init: fn, //          
                insert: fn,
                prepatch: fn,
                destroy: fn
              },
              scopedSlots: { //         ,         VNode
                slotName: slotFn
              }
            },
            children: [ //       
              tag: 'template',
              propsData: undefined, // props  
              listeners: undefined,
              data: {
                slot: 'hello'
              },
              children: [ VNode ],
              parent: undefined,
              context: componentContext //       
              // ...
            ] 
          }
        }
      ],
      // ...
    }
    vue 에서 구성 요 소 는 페이지 구조의 기본 단원 이다.상기 VNode 에서 알 수 있 듯 이 VNode 페이지 의 등급 구 조 는 test 구성 요소 에서 끝나 고 test 구성 요소 children 처 리 는 하위 구성 요소 초기 화 과정 에서 처 리 될 것 이다.하위 구성 요소 구조 방법 조립 과 속성 을 vue-dev\src\\core\vdom\\create-component.js createComponent 방법 에 통합 합 니 다.구성 요소 의 정례 화 호출 입 구 는 vue-dev\src\\core\vdom\patch.js createComponent 방법 에 있 습 니 다.
    7.하위 구성 요소 상태 초기 화
    인 스 턴 스 화 서브 구성 요 소 는 initRender->resolveSlots 방법 에서 하위 구성 요소 슬롯 노드 를 구성 요소 역할 영역 vm 에 마 운 트 하고 마 운 트 형식 은 vm.$slots = {slotName: [VNode]} 형식 입 니 다.
    8.하위 구성 요소 컴 파일 단계
    하위 구성 요 소 는 컴 파일 단계 에서 slot 노드 를 다음 과 같은 AST 구조 로 컴 파일 합 니 다.
    
    {
      tag: 'h1',
      parent: undefined,
      children: [
        {
          tag: 'slot',
          slotName: "\"hello\"",
          // ...
        }
      ],
      // ...
    }
    9.하위 구성 요소 생 성 렌 더 링 방법
    생 성 된 렌 더 링 방법 은 다음 과 같다.그 중에서 _trenderSlot 방법의 약자 로 renderSlot 방법 에서 우 리 는 슬롯 내용 과 슬롯 점 을 직관 적 으로 연결 할 수 있다.
    
    //     
    with(this){
      return _c('h1',[ _t("hello") ], 2)
    }
    
    //     :vue-dev\src\core\instance\render-helpers\render-slot.js
    export function renderSlot (
      name: string,
      fallback: ?Array<VNode>,
      props: ?Object,
      bindObject: ?Object
    ): ?Array<VNode> {
      const scopedSlotFn = this.$scopedSlots[name]
      let nodes
      if (scopedSlotFn) { // scoped slot
        props = props || {}
        if (bindObject) {
          if (process.env.NODE_ENV !== 'production' && !isObject(bindObject)) {
            warn(
              'slot v-bind without argument expects an Object',
              this
            )
          }
          props = extend(extend({}, bindObject), props)
        }
        //      ,    VNode
        nodes = scopedSlotFn(props) || fallback
      } else {
        //         VNode
        nodes = this.$slots[name] || fallback
      }
    
      const target = props && props.slot
      if (target) {
        return this.$createElement('template', { slot: target }, nodes)
      } else {
        return nodes
      }
    }
    역할 영역 슬롯 과 구명 슬롯 의 차이
    
    <!-- demo -->
    <div id='app'>
      <test>
          <template slot="hello" slot-scope='scope'>
            {{scope.hello}}
          </template>
      </test>
    </div>
    <script>
        var vm = new Vue({
            el: '#app',
            components: {
                test: {
                    data () {
                        return {
                            hello: '123'
                        }
                    },
                    template: '<h1>' +
                        '<slot name="hello" :hello="hello"></slot>' +
                      '</h1>'
                }
            }
        })
    
    </script>
    역할 도 메 인 슬롯 은 일반 슬롯 에 비해 슬롯 내용 이 하위 구성 요소 역할 도 메 인 변 수 를 얻 을 수 있다 는 차이 가 있 습 니 다.하위 구성 요소 변 수 를 주입 해 야 하기 때문에 구명 슬롯 에 비해 역할 영역 슬롯 은 다음 과 같은 몇 가지 차이 가 있 습 니 다.
    역할 도 메 인 슬롯 은 렌 더 링 방법 을 조립 할 때 주입 역할 도 메 인 을 포함 하 는 방법 을 생 성 합 니 다.createElement 에 비해 VNode 을 생 성 하고 주입 역할 도 메 인 방법 패키지 가 한 층 더 생 성 되 었 습 니 다.이 는 슬롯 VNode 역할 도 메 인 슬롯 은 하위 구성 요소 가 VNode 을 생 성 할 때 생 성 되 며,서명 슬롯 은 부모 구성 요소 가 VNode 을 만 들 때 생 성 됩 니 다._uresolveScopedSlots 으로 노드 설정 항목 을 {scopedSlots: {slotName: fn}} 형식 으로 전환 하 는 역할 을 한다.
    
    with (this) {
            return _c('div', {
                attrs: {
                    "id": "app"
                }
            }, [_c('test', {
                scopedSlots: _u([{
                    key: "hello",
                    fn: function(scope) {
                        return [_v("
    " + _s(scope.hello) + "
    ")] } }]) })], 1) }
    하위 구성 요소 가 초기 화 될 때 서명 슬롯 노드 를 처리 하고 구성 요소 $slots 에 마 운 트 합 니 다.역할 영역 슬롯 은 renderSlot 에서 직접 호출 됩 니 다.
    그 밖 에 다른 절 차 는 대체로 같다.슬롯 역할 체 제 는 이해 하기 어렵 지 않 습 니 다.관건 은 템 플 릿 분석 과 render 함수 생 성 이라는 두 단계 의 내용 이 비교적 많 고 절차 가 길 며 이해 하기 어렵 습 니 다.
    10.사용 기교
    이상 의 분석 을 통 해 슬롯 처리 절 차 를 대충 알 수 있 습 니 다.작업 중 대부분 은 템 플 릿 으로 vue 코드 를 작성 하지만 어떤 때 는 템 플 릿 에 한계 가 있 기 때문에 render 방법 을 통 해 vue 의 구성 요소 추상 능력 을 확대 해 야 합 니 다.그러면 render 방법 에서 우리 의 슬롯 사용 방법 은 다음 과 같다.
    10.1.서명 슬롯
    슬롯 처 리 는 일반적으로 두 조각 으로 나 뉜 다.
  • 부모 구성 요소:부모 구성 요 소 는 템 플 릿 으로 컴 파일 된 렌 더 링 방법 만 쓰 면 됩 니 다.즉,슬롯 slot 이름
  • 을 지정 합 니 다.
  • 하위 구성 요소:하위 구성 요소 일 때 부모 구성 요소 초기 화 단계 에서 생 성 된 VNode 을 직접 가 져 오기 때문에 하위 구성 요 소 는 slot 탭 을 부모 구성 요소 로 대체 하여 생 성 된 VNode 으로 만 들 수 있 습 니 다.하위 구성 요 소 는 초기 화 상태 에서 구성 요소 $slots 속성 에 서명 슬롯 을 마 운 트 합 니 다.
  • 
    <div id='app'>
    <!--  <test>-->
    <!--    <template slot="hello">-->
    <!--      123-->
    <!--    </template>-->
    <!--  </test>-->
    </div>
    <script>
      new Vue({
        // el: '#app',
        render (createElement) {
          return createElement('test', [
            createElement('h3', {
              slot: 'hello',
              domProps: {
                innerText: '123'
              }
            })
          ])
        },
        components: {
          test: {
            render(createElement) {
              return createElement('h1', [ this.$slots.hello ]);
            }
            // template: '<h1>' +
            //   '<slot name="hello"></slot>' +
            //   '</h1>'
          }
        }
      }).$mount('#app')
    </script>
    10.2 역할 영역 슬롯
    역할 영역 슬롯 의 사용 이 비교적 유연 하여 하위 구성 요소 상 태 를 주입 할 수 있 습 니 다.역할 영역 슬롯+render 방법 은 2 차 구성 요소 의 패 키 징 에 매우 큰 역할 을 합 니 다.밤 을 들 어 ElementUI table 구성 요 소 를 JSON 데이터 로 포장 할 때 역할 영역 슬롯 의 용도 가 매우 크다.
    
    <div id='app'>
    <!--  <test>-->
    <!--    <span slot="hello" slot-scope='scope'>-->
    <!--      {{scope.hello}}-->
    <!--    </span>-->
    <!--  </test>-->
    </div>
    <script>
      new Vue({
        // el: '#app',
        render (createElement) {
          return createElement('test', {
            scopedSlots:{
              hello: scope => { //           ,                   
                return createElement('span', {
                  domProps: {
                    innerText: scope.hello
                  }
                })
              }
            }
          })
        },
        components: {
          test: {
            data () {
              return {
                hello: '123'
              }
            },
            render (createElement) {
              //               function,        VNode
              let slotVnode = this.$scopedSlots.hello({ hello: this.hello })
              return createElement('h1', [ slotVnode ])
            }
            // template: '<h1>' +
            //   '<slot name="hello" :hello="hello"></slot>' +
            //   '</h1>'
          }
        }
      }).$mount('#app')
    
    </script>
    이상 은 Vue 슬롯 실현 원리 에 대한 상세 한 내용 입 니 다.Vue 슬롯 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 해 주 십시오!

    좋은 웹페이지 즐겨찾기