vue组件——vue简单说

缺乏、安全感 2022-03-14 15:16 288阅读 0赞

目录

  • 组件基础示例:
  • 组件间传递数据
    • props基础示例:
    • $emit基础示例:
    • bus的使用
    • 使用$refs子组件索引
  • 使用slot分发内容
    • 具名Slot
    • 作用域插槽
    • 访问slot
  • 组件的高级应用
    • 递归组件
    • 内联模板
    • 动态组件
    • 异步组件
  • 其他
    • $nextTick

vue组件:可复用的 Vue 实例,扩展 HTML 元素,封装可重用的代码

组件基础示例:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title></title>
  6. <script src="https://cdn.bootcss.com/vue/2.6.6/vue.min.js"></script>
  7. </head>
  8. <body>
  9. <div id="app">
  10. <my-component></my-component>
  11. </div>
  12. </body>
  13. <script> Vue.component('my-component',{ template: '<div>基础组件示例</div>' }) var app = new Vue({ el: "#app" }) </script>
  14. </html>

运行结果:在这里插入图片描述

其中组件部分HTML等价于:

  1. <div id="app">
  2. <div is="my-component"></div>
  3. </div>

上面两种的有一点点区别,就是收到HTML的限制,

下只允许,
,,这个时候table下直接使用组件是无效的,可以使用特殊的属性挂载组件,即 is=“my-component”。

组件间传递数据

常用父子组件传值过程汇总:
最常用:props、$emit

props

$emit

父组件

子组件

不推荐使用,vue.js 1.x的非父子通信:$broadcast、$dispatch

$broadcast

$dispatch

有监听的父组件

有监听的子组件

推荐使用:vue.js 2.x中非父子通信方式:使用一个空的Vue实例作为中央事件总线(bus)

bus.$emit

bus.$on

bus.$on

bus.$emit

组件A

bus

组件B

不推荐使用:父链,子链

$children

$parent

所有父组件

所有子组件

推荐你使用:子组件索引

$refs

子组件

父组件

props基础示例:

  1. <div id="app">
  2. <my-component warning-text="提示信息"></my-component>
  3. </div>
  4. <script> Vue.component('my-component', { props: ['warningText'], template: '<div>{ {warningText}}</div>' }) var app = new Vue({ el: "#app" }) </script>

运行结果:在这里插入图片描述

传递来自父级的动态数据,使用指令v-bind语法糖: ,当父级数据变化,也会传递给子组件。如下示例:

  1. <div id="app">
  2. <input type="text" v-model="parentMessage">
  3. <my-component :message="parentMessage"></my-component>
  4. </div>
  5. <script> Vue.component('my-component', { props: ['message'], template: '<div>{ {message}}</div>' }) var app = new Vue({ el: "#app", data: { parentMessage: '1234' } }) </script>

运行结果:
在这里插入图片描述

关于传递数据的特点

  1. <div id="app">
  2. <h2 v-text="text"></h2>
  3. <h2 is="my-component7" message-kkk="[1,2,3]"></h2>
  4. <h2 is="my-component7" :message-kkk="[1,2,3]"></h2>
  5. </div>
  6. <script> Vue.component("my-component7", { props: ["messageKkk"], template: '<div>{ {messageKkk.length}}</div>' }); new Vue({ el: '#app', data: { text: '如果你要直接传递数字、布尔值、数组、对象,而且不使用 v-bind \ ,传递的仅仅是字符串,尝试下面的示例来对比:\n\ <h2 is="my-component7" message-kkk="[1,2,3]"></h2>\ <h2 is="my-component7" :message-kkk="[1,2,3]"></h2>', } }); </script>

注:字符串和数组长度的区别
运行结果:
在这里插入图片描述

props数据验证:

  1. Vue.component('my-component', {
  2. props: {
  3. // 必须是数字类型
  4. propA: Number,
  5. // 必须是数字或字符类型
  6. propB: [String, Number],
  7. // 布尔值,如果没有定义,默认值是true
  8. propC: {
  9. type: Boolean,
  10. default: true
  11. },
  12. // 数字类型,而且必传
  13. propD: {
  14. type: Number,
  15. required: true
  16. },
  17. // 如果数组或对象类型,默认值必须是一个函数来返回
  18. propE: {
  19. type: Array,
  20. default: function(){
  21. return []
  22. }
  23. },
  24. // 自定义一个验证函数
  25. propF: {
  26. validator: function(value){
  27. return value > 10;
  28. }
  29. }
  30. },
  31. })

type的类型可以是:String、Number、Boolean、Object、Array、Function

$emit基础示例:

  1. <div id="app10">
  2. <h2 v-text="text"></h2>
  3. <p>总数 : {
  4. {total}} </p>
  5. <my-component10 @increase="handleGetTotal" @reduce="handleGetTotal">
  6. </my-component10>
  7. </div>
  8. <script> Vue.component("my-component10", { template: '<div><button @click="handleIncrease"> + l </button><button @click= "handleReduce ">-1</button></div>', data() { return { counter: 0 } }, methods: { handleIncrease: function () { this.counter++; this.$emit('increase', this.counter); }, handleReduce: function () { this.counter--; this.$emit('reduce', this.counter); }, } }); new Vue({ el: '#app10', data: { text: '子组件有两个按钮,分别实现加 1 和减 l 的效果 , 在改变组件的 data “ counter",\ 把它传递给父组件, 父组件用 v-on:increase 和 v-on:reduce ', total: 0 }, methods: { handleGetTotal: function (total) { this.total = total; } } }); </script>

运行结果:
在这里插入图片描述

使用v-model,简化父子组件双向绑定案例:

  1. <div id="app12">
  2. <h2 v-text="text"></h2>
  3. <p>父组件total:{
  4. {total}}</p>
  5. 子组件total:<h2 is="my-component12" v-model="total"></h2>
  6. <button @click="add"></button>
  7. </div>
  8. <script> Vue.component('my-component12', { props: ['value'], template: '<input v-model="value" @input="updateValue" />', methods: { updateValue: function (event) { this.$emit('input', event.target.value); } } }) new Vue({ el: "#app12", data: { text: "v-model 还可以用来创建自定义的表单输入组件, 进行数据双向绑定", total: 0 }, methods: { add: function () { this.total++; } } }); </script>

运行结果:
在这里插入图片描述

bus的使用

  1. <div id="app13">
  2. <h2 v-text="text"></h2>
  3. 收到的信息:{
  4. {message}}
  5. <component-a></component-a>
  6. </div>
  7. <script> var bus = new Vue(); Vue.component('component-a', { template: '<button @click="handleEvent">传递事件</button>', methods: { handleEvent: function () { bus.$emit('on-message', ' 来自组件 component-a 的内 容 '); } } }); new Vue({ el: '#app13', data: { text: '推荐使用一个空的 Vue 实例作为中央事件总线( bus ),也就是一个中介', message: '' }, mounted: function () { var _this = this; bus.$on('on-message', function (msg) { this.message = msg; }); } }); </script>

点击按钮后的结果:
在这里插入图片描述

使用$refs子组件索引

Vue提供了子组件索引的方法,用特殊的属性ref为子组件指定一个索引名称。

  1. <div id="app13">
  2. <button @click="handleRef">通过ref获取子组件实例</button>
  3. <p>获取到的子组件数据:{
  4. {tempMsg}}</p>
  5. <component-a ref="comA"></component-a>
  6. </div>
  7. <script> Vue.component('component-a', { template: '<div>子组件</div>', data: function(){ return { message: '子组件内容' } } }); new Vue({ el: '#app13', data: { tempMsg:'' }, methods: { handleRef:function(){ this.tempMsg = this.$refs.comA.message; } } }); </script>

点击按钮后的执行结果:
在这里插入图片描述

使用slot分发内容

例子:

  1. <app>
  2. <menu-main></menu-main>
  3. <menu-sub></menu-sub>
  4. <div class="container">
  5. <menu-left></menu-left>
  6. <container></container>
  7. </div>
  8. <app-footer></app-footer>
  9. </app>

如上组件嵌套,就会使用到slot,这个叫内容分发。有两个特点:

  1. 不知道他的挂载点会有什么内容。
  2. 组件很可能有自己的模板。

基础示例:

  1. <div id="app18">
  2. <component-a>
  3. <p>分发的内容</p>
  4. <p>更多分发的内容</p>
  5. </component-a>
  6. </div>
  7. <script> Vue.component('component-a', { template: '\ <div>\ <slot>\ <p>如果父组件没有插入内容,默认显示这个</p>\ </slot>\ </div>' }); new Vue({ el: '#app18' }); </script>

运行结果:
在这里插入图片描述

具名Slot

可以指定分发多个内容

  1. <div id="app19">
  2. <component-a>
  3. <h2 slot="header">标题</h2>
  4. <p>分发的内容</p>
  5. <p>更多分发的内容</p>
  6. <div slot="footer">底部</div>
  7. </component-a>
  8. </div>
  9. <script> Vue.component('component-a', { template: '<div class="container">\ <div class="header">\ <slot name="header"></slot>\ </div>\ <div class="main">\ <slot></slot>\ </div>\ <div class="footer">\ <slot name="footer"></slot>\ </div>\ </div>' }); new Vue({ el: '#app19' }); </script>

运行结果:
在这里插入图片描述

作用域插槽

  1. <div id="app20">
  2. <book-list :books="books">
  3. <template slot="book" scope="props">
  4. <li>{
  5. {props.bookName}}</li>
  6. </template>
  7. </book-list>
  8. </div>
  9. <script> Vue.component('book-list', { props: { books: { type: Array, default: function () { return []; } } }, template:'<ul>\ <slot name="book" v-for="book in books" :book-name="book.name">\ </slot>\ </ul>' }); new Vue({ el: '#app20', data: { books: [ { name:'javascript设计模式'}, { name:'javascript权威指南'}, { name:'javascript入门到放弃'} ] } }); </script>

注::book-name=“book.name” 与 props.bookName对应
运行结果:
在这里插入图片描述

访问slot

vue2.X 提供了用来访问slot分发内容的方法$slots,如下示例:

  1. <div id="app19">
  2. <component-a>
  3. <h2 slot="header">标题</h2>
  4. <p>分发的内容</p>
  5. <p>更多分发的内容</p>
  6. <div slot="footer">底部</div>
  7. </component-a>
  8. </div>
  9. <script>
  10. Vue.component('component-a', {
  11. template: '<div class="container">\ <div class="header">\ <slot name="header"></slot>\ </div>\ <div class="main">\ <slot></slot>\ </div>\ <div class="footer">\ <slot name="footer"></slot>\ </div>\ </div>',
  12. mounted: function(){
  13. var header = this.$slots.header;
  14. var main = this.$slots.default;
  15. var footer = this.$slots.footer;
  16. console.log(footer); // [fe]
  17. console.log(footer[0].elm.innerHTML); // 底部
  18. }
  19. });
  20. new Vue({
  21. el: '#app19'
  22. });
  23. </script>

运行结果:
在这里插入图片描述

组件的高级应用

递归组件

示例如下:

  1. <div id="app19">
  2. <child-component></child-component>
  3. </div>
  4. <script>
  5. Vue.component('child-component', {
  6. props: {
  7. count: {
  8. type: Number,
  9. default: 1
  10. }
  11. },
  12. template: '<div class="child">\ <p>第{ {count}}层子组件</p>\ <child-component\ :count="count+1"\ v-if="count < 3"></child-component>\ </div>'
  13. });
  14. new Vue({
  15. el: '#app19'
  16. });
  17. </script>

注: 必须各一个条件显示递归数量,否则会抛出错误:max stack size exceeded
运行结果:
在这里插入图片描述

内联模板

vue提供了一个内联模板的功能,在使用组件是,给标签使用inline-template特性,组件就会把内容当做模板,而不是内容分发。示例如下:

  1. <div id="app19">
  2. <child-component inline-template>
  3. <div>
  4. <h1>父组件中的子组件模板</h1>
  5. <p>{ { message}}</p>
  6. <p>{ { msg}}</p>
  7. <p>{ { commonData}}</p>
  8. </div>
  9. </child-component>
  10. </div>
  11. <script>
  12. Vue.component('child-component', {
  13. data: function () {
  14. return {
  15. msg: '子组件声明的数据',
  16. commonData: '同名数据,子组件数据'
  17. }
  18. }
  19. });
  20. new Vue({
  21. el: '#app19',
  22. data: {
  23. message: '父组件声明的数据',
  24. commonData: '同名数据,父组件数据'
  25. }
  26. });
  27. </script>

注: 在父组件声明的数据message和子组件声明的msg,两个都会被渲染。如果同名,子组件数据优先使用!
在这里插入图片描述

动态组件

Vue提供了一个特殊的元素,用来动态挂载不同组件,使用is特性来选择要挂载的组件。示例如下:

  1. <div id="app19">
  2. <component :is="currentView"></component>
  3. <button @click="handleChangeView('A')">切换comA组件</button>
  4. <button @click="handleChangeView('B')">切换comB组件</button>
  5. <button @click="handleChangeView('C')">切换comC组件</button>
  6. </div>
  7. <script>
  8. new Vue({
  9. el: '#app19',
  10. components: {
  11. comA: {
  12. template: '<h1>组件A</h1>'
  13. },
  14. comB: {
  15. template: '<h1>组件B</h1>'
  16. },
  17. comC: {
  18. template: '<h1>组件C</h1>'
  19. }
  20. },
  21. data: {
  22. currentView: 'comA',
  23. },
  24. methods: {
  25. handleChangeView: function(component){
  26. this.currentView = 'com' + component;
  27. }
  28. }
  29. });
  30. </script>

运行效果:
在这里插入图片描述

异步组件

  1. <div id="app18">
  2. <component-a></component-a>
  3. </div>
  4. <script>
  5. Vue.component('component-a', function(resolve,reject){
  6. window.setTimeout(function(){
  7. resolve({
  8. template: '<div>我是异步组件渲染的</div>'
  9. })
  10. }, 2000)
  11. });
  12. new Vue({
  13. el: '#app18'
  14. });
  15. </script>

注: setTImeout是为了掩饰异步,工厂函数接收一个resolve回调。也可以调用reject(reason)加载失败。
运行结果:
在这里插入图片描述

其他

$nextTick

$nextTick:用来知道什么时候DOM更新完毕。异步更新DOM,当DOM没更新完时,div还没被创建。
实例如下:

  1. <div id="app18">
  2. <div id="div" v-if="showDiv">这是一段文字</div>
  3. <button @click="getText">获取文本内容</button>
  4. </div>
  5. <script>
  6. new Vue({
  7. el: '#app18',
  8. data: {
  9. showDiv: false
  10. },
  11. methods: {
  12. getText: function(){
  13. this.showDiv = true;
  14. // var text = document.getElementById('div').innerHTML;
  15. // 报错了,因为未找到元素document.getElementById('div')为null,所以innerHTML属性访问出错。
  16. // console.log(text)
  17. this.$nextTick(function(){
  18. var text = document.getElementById('div').innerHTML;
  19. console.log(text) // 这是一段文字
  20. })
  21. }
  22. }
  23. });
  24. </script>

运行结果自己试下!!!


本篇完。。。有问题联系我改。

发表评论

表情:
评论列表 (有 0 条评论,288人围观)

还没有评论,来说两句吧...

相关阅读