VueJS(八)

    技术2024-12-23  13

    上次学到作用域

    首先需要明确slot分发的内容是在父组件上的 所谓内容在父组件和子组件的内容之分,就是看在哪里编译 在子组件上绑定的话写在组件注册内容内部,父组件绑定是写在注册vue实例内容中

    slot的用法 slot的意思是插槽,用于内容分发,就是混合父组件的内容和子组件的模板

    单个slot 在子组件内使用特殊的<slot>元素就可以为这个子组件开启一个slot(插槽) 在父组件模板里面插入在子组件标签内的所有内容将代替子组件的<slot>标签及它的内容

    <body> <div id="app"> <child-component> <p>分发的内容</p> <p>更多</p> </child-component> </div> <script> Vue.component('child-component',{ template:'\ <div>\ <slot>\ <p>如果没有内容,这句话将默认出现</p>\ </slot>\ </div>' }); var app = new Vue({ el:'#app' }) </script> </body>

    来看看一个案例,就是一个普通的注册组件,然后使用的过程,之前一般的组件注册内容,在写了template属性后,里面的内容会完全替代使用组件标签时里面的内容,但是这里的template内容添加了slot的属性后,就变得不一样了,他不会直接完全替代原本组件标签中的内容,只会在组件标签原本无内容时替换 子组件child-component的模板内定义了一个slot元素,并且使用一个p作为默认内容,在父组件没有使用slot的

    具名slot 给slot元素指定一个name后可以分发多个内容,具名slot可以与单个slotslot共存 额,我理解错了,slot的作用不是为了禁止template里面的内容代替组件标签内容,而是slot相当于一个槽孔,插槽,让组件标签内的内容加入到slot里面,然后再把template的内容替换组件标签内容,而槽孔原来的内容会被替代,除非组件标签原来没内容,芜湖!!!

    <body> <div id="app"> <child-component> <h2 slot="header">标题</h2> <p>正文内容</p> <p>更多正文内容</p> <div slot="footer">底部消息</div> </child-component> </div> <script> Vue.component('child-component',{ template:'\ <div class="xx">\ <div class="x">\ <slot name="footer"></slot>\ </div>\ <div>\ <slot></slot>\ </div>\ <div>\ <slot name="header"></slot>\ </div>\ </div>' }); //main那个是默认slot var app = new Vue({ el:'#app' }) </script> </body>

    这里经过渲染后的结果就是:

    <div class="xx"> <div class="x"> <div>底部消息</div> </div> <div> <p>正文内容</p> <p>更多正文内容</p> </div> <div> <h2>标题</h2> </div> </div>

    作用域插槽 作用域插槽是一种特殊的slot,使用一个可以复用的模板替换已渲染元素

    <body> <div id="app"> <child-component> <template scope="props"> <p>来自父组件的内容</p> <p>{{props.msg}}</p> </template> </child-component> </div> <script> Vue.component('child-component',{ template:'\ <div class="container">\ <slot msg="来自子组件的内容"></slot>\ </div>' }); var app = new Vue({ el:'#app' }) </script> </body>

    分析: 渲染后的结果是:

    <div id="app"> <div class="container"> <p>来自父组件的内容</p> <p>来自子组件的内容</p> </div> </div>

    在slot元素上有一个类似props传递数据给组件的写法msg=“xxx”,将数据传到了插槽中。父组件使用了template元素,而且拥有一个scope=“props”的特性,这里的props可以是任意变量,并不代表什么绑定。template内通过变量props访问来自子组件插槽的数据msg

    作用域插槽更具有代表性的用例是列表组件,允许组件自定义应该如何渲染列表的每一项

    <body> <div id="app"> <my-qian :books="books"> <template slot="book" scope="props"> <li> {{props.bookName}} </li> </template> </my-qian> </div> <script> Vue.component('my-qian',{ props:{ books:{ type:Array, default:function(){ return []; } } }, template:'\ <ul>\ <slot name="book" v-for="book in books" :book-name="book.name">\ </slot>\ </ul>' }); var app = new Vue({ el:'#app', data:{ books:[ { name: 'xxxxx'}, { name: 'yyyyy'}, { name: 'zzzzz'} ] } }) </script> </body>

    子组件my-qian接受一个来自父级的prop数组books,并且将它在叫做book的插槽中使用v-for循环,并使用点出bookName的值3次,这个for循环是子组件的插槽中进行的

    访问slot 未来就是现在!

    使用$slot可以访问被slot分发的内容

    <body> <div id="app"> <my-qian> <h2 slot="header">标题</h2> <p>正文</p> <p>more</p> <div slot="footer">底部信息</div> </my-qian> </div> <script> Vue.component('my-qian',{ template:'\ <div class="container">\ <div class="header"></slot>\ <slot name="header"></slot>\ </div>\ <div class="main">\ <slot></slot>\ </div>\ <div class="footer">\ <slot name="footer"></slot>\ </div>\ </div>', mounted:function(){ var header = this.$slots.header; var main = this.$slots.default; var footer = this.$slots.footer; // console.log(footer); console.log(footer[0].elm.innerHTML); } }); var app = new Vue({ el:'#app' }) </script> </body>

    这里面通过mounted里面的内容访问了几个具名slot还有匿名,匿名的通过this.$slots.defaut来访问,其他的都是this.$slot.+名字来访问,然后如果是具体的名字,需要语句console.log(footer[0].elm.innerHTML); 如果是获取所有信息在控制板上,就是通过console.log(footer);

    $nextTick 一个div,默认用v-if隐藏之,点击按钮,改变v-if值使之显现,同时也就获取到了这个div的内容,但是如果值为负的时候,是无法获取的,之前说和v-show的区别的时候也讲过了,这个是不曾渲染的在为假时

    <body> <div id="app"> <div id="div" v-if="showDiv">这是一段问了</div> <button @click="getText">获取内容</button> </div> <script> var app = new Vue({ el:'#app', data:{ showDiv:false }, methods:{ getText:function(){ this.showDiv = true; var text = document.getElementById('div').innerHTML; console.log(text); } } }) </script> </body>

    像上面这样直接获取div的内容的话,是会报错的,因为根本没有渲染

    vue在观察到数据变化的时候并不是直接更新DOM,而是开启一个队列,并缓冲在同一时间循环中发生的所有数据改变。在缓冲的时候会去除重复数据,从而避免不需要的计算和DOM操作。然后在下一个事件循环tick中,vue刷新队列并执行工作 所以如果是一个for循环来动态改变数据100次,他只会应用最后一次改变 $nextTick可以用来知道DOM是什么时候更新完成的

    <body> <div id="app"> <div id="div" v-if="showDiv">这是一段文本</div> <button @click="getText">获取内容</button> </div> <script> var app = new Vue({ el:'#app', data:{ showDiv:false }, methods:{ getText:function(){ this.showDiv = true; this.$nextTick(function(){ var text = document.getElementById('div').innerHTML; console.log(text); }); } } }) </script> </body>

    这样把获取div的语句放进$nextTick里面就可以了,不会继续报错

    手动挂载实例 一般来说都是new Vue()来创建实例。如果需要动态地创建一些Vue实例的话,就需要用到Vue.extend和$mount两个方法来手动挂载一个实例

    Vue.extend是基础Vue构造器,创建一个“子类”,参数是一个包含组件选项的对象。 如果Vue实例在实例化的时候没有收到el选项,他就处于一个未挂载的状态,没有关联的DOM元素。可以使用$mount()手动地挂载一个未挂载的实例

    <body> <div id="mount-div"> </div> <script> var MyComonent = Vue.extend({ template:'<div>Hello:{{name}}</div', data:function(){ return { name : 'Ak' } } }); new MyComonent().$mount('#mount-div'); </script> </body>

    具体,明天再分析

    Processed: 0.010, SQL: 9