1. Sample code<!-- Subcomponent comA --> <template> <div class='demo'> <slot><slot> <slot name='test'></slot> <slot name='scopedSlots' test='demo'></slot> </div> </template> <!-- Parent component --> <comA> <span>This is the default slot</span> <template slot='test'>This is a named slot</template> <template slot='scopedSlots' slot-scope='scope'>This is a scoped slot (old version) {{scope.test}}</template> <template v-slot:scopedSlots='scopeProps' slot-scope='scope'>This is a scoped slot (new version) {{scopeProps.test}}</template> </comA> 2. See the essence through the phenomenonThe role of slots is to achieve content distribution. To achieve content distribution, two conditions are required:
3. Implementation Principle The order of instantiation of From the above process, we can infer that: 1. The parent component template is parsed before the child component, so the parent component will first get the slot template content 2. The subcomponent template is parsed later, so when the subcomponent calls 3. The scope slot can obtain variables in the subcomponent, so the The entire slot processing phase is roughly divided into three steps:
Taking the following code as an example, the operation process of the slot is briefly outlined. <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. Parent component compilation phase Compilation is to parse the template file into an { tag: 'test', scopedSlots: { // scope slot // slotName: ASTNode, // ... } children: [ { tag: 'template', // ... parent: parentASTNode, children: [ childASTNode ], // slot content child node, i.e. text node 123 slotScope: undefined, // Scope slot binding value slotTarget: "\"hello\"", // Named slot name slotTargetDynamic: false // Is it a dynamically bound slot// ... } ] } 5. Parent component generates rendering method According to the with(this){ return _c('div',{attrs:{"id":"app"}}, [_c('test', [ _c('template',{slot:"hello"},[_v("\n 123\n ")])],2) ], 1) } 6. Parent component generates VNode Call the { tag: 'div', parent: undefined, data: { // Store VNode configuration items attrs: { id: '#app' } }, context: componentContext, // component scope elm: undefined, // real DOM element children: [ { tag: 'vue-component-1-test', children: undefined, // The component is the smallest unit of the page, and the slot content is parsed in the child component parent: undefined, componentOptions: { // Component configuration item Ctor: VueComponentCtor, // Component construction method data: { hook: { init: fn, //Instantiate component calling method insert: fn, prepatch: fn, destroy: fn }, scopedSlots: { //Scope slot configuration item, used to generate scope slot VNode slotName: slotFn } }, children: [ // Component slot node tag: 'template', propsData: undefined, // props parameters listeners: undefined, data: { slot: 'hello' }, children: [ VNode ], parent: undefined, context: componentContext // parent component scope // ... ] } } ], // ... } In 7. Subcomponent state initialization When instantiating a subcomponent, the subcomponent slot node will be mounted to the component scope 8. Subcomponent compilation phase During the compilation phase, the subcomponent will compile { tag: 'h1', parent: undefined, children: [ { tag: 'slot', slotName: "\"hello\"", // ... } ], // ... } 9. Subcomponent generation rendering method The generated rendering method is as follows, where // Rendering method with(this){ return _c('h1',[ _t("hello") ], 2) } // Source code path: 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) } //Scope slot, get slot VNode nodes = scopedSlotFn(props) || fallback } else { // Get the slot normal slot VNode nodes = this.$slots[name] || fallback } const target = props && props.slot if (target) { return this.$createElement('template', { slot: target }, nodes) } else { return nodes } } Difference between scoped slots and named slots <!-- 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> The main difference between scoped slots and ordinary slots is that the slot content can obtain subcomponent scope variables. Due to the need to inject subcomponent variables, scoped slots are different from named slots in the following ways: When assembling the rendering method, the scope slot generates a method that contains the injection scope. Compared with with (this) { return _c('div', { attrs: { "id": "app" } }, [_c('test', { scopedSlots: _u([{ key: "hello", fn: function(scope) { return [_v("\n " + _s(scope.hello) + "\n ")] } }]) })], 1) } When the subcomponent is initialized, the named slot node is processed and mounted to the component Other than that, the process is pretty much the same. The mechanism of slots is not difficult to understand, but the key is the two steps of template parsing and rendering function generation, which are more complex and have a longer process and are more difficult to understand. 10. Usage Tips Through the above analysis, we can roughly understand the slot processing flow. Most of the work is done using templates to write 10.1. Named SlotsSlot processing is generally divided into two parts:
<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. Scoped Slots Scoped slots are more flexible to use and can inject subcomponent states. Scoped slots + <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 => { // In the parent component rendering method, the final converted scope slot method is consistent with this writing method return createElement('span', { domProps: { innerText: scope.hello } }) } } }) }, components: test: { data () { return { hello: '123' } }, render (createElement) { // The scope slot parent component passes a function, which needs to be called manually to generate a 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> The above is a brief discussion of the detailed content of the implementation principle of Vue slots. For more information about Vue slots, please pay attention to other related articles on 123WORDPRESS.COM! You may also be interested in:
|
<<: A friendly alternative to find in Linux (fd command)
>>: Using puppeteer to implement webpage screenshot function on linux (centos)
Copy the following code to the code area of Drea...
Install Docker Desktop Download address: Docker D...
Install crontab yum install crontabs CentOS 7 com...
During the project, I started using the js reques...
Table of contents 1. Overview 1. Principle 2. Imp...
1. Syntax TIMESTAMPDIFF(unit,begin,end); Returns ...
Awk is an application for processing text files, ...
There are the following log files in MySQL: 1: re...
1. Install mysql5.6 docker run mysql:5.6 Wait unt...
Table of contents Thoughts triggered by an online...
The following are all performed on my virtual mac...
Table of contents Class Component Functional Comp...
Table of contents 1. Prototype chain inheritance ...
Copy code The code is as follows: <!DOCTYPE ht...
Table of contents 1. JavaScript can change all HT...