vue组件化深入--day03

本文详细探讨了Vue中的自定义组件标签、动态组件与异步组件的使用,包括`is`关键字、`keep-alive`的属性和函数、以及组件间的交互。还介绍了如何处理异步组件的加载状态,并通过实例展示了父子组件间的通信和依赖注入。
摘要由CSDN通过智能技术生成

个人blog-1: 拾忆生活
个人blog-2: 极简-拾忆生活
欢迎大家来踩,同步更新


vue–自定义 component 标签

  • 先仔细看下components命名规则对比

  • is 关键字

    • <component :is="xxx"></component>
  • ComponentA: ComponentA 的缩写---->ComponentA

  • 即这个变量名同时是:

    • 用在模板中的自定义元素的名称
    • 包含了这个组件选项的变量名
import ComponentA from './ComponentA.vue'

export default {
  components: {
    ComponentA  
  },
  // ...
}

实例1:

<script type="text/javascript">
    var HelloTom = {
      data: function(){
        return {
          msg: 'HelloTom'
        }
      },
      template: '<div>{{msg}}</div>'
    };
    var HelloJerry = {
      data: function(){
        return {
          msg: 'HelloJerry'
        }
      },
      template: '<div>{{msg}}</div>'
    };
    var vm = new Vue({
      el: '#app',
      data: {
      },
      components: {
        'hello-tom': HelloTom,
        'hello-jerry': HelloJerry
      }
    });
  </script>

动态组件 & 异步组件

的’is’ 关键字

  • ′ i s ′ 关 键 字 \color{red}'is' 关键字 is 用来动态切换组件
    • 其属性值可以是 、也可以是 函数
    • 绑定key数据,根据key的值不同,调用不同的组件。

例1:

<div id="app">
    <component :is="key"></component>
</div>

var componentA = {
    template: `<div style="color:red">我是A组件</div>`
}
var componentB = {
    template: `<div style="color:blank">我是B组件</div>`
}
var componentC = {
    template: `<div style="color:pink">我是C组件</div>`
}
var app = new Vue({
    el: '#app',
    components: {
        "comA": componentA,
        "comB": componentB,
        "comC": componentC
    },
    data:{
        key:'comB'
    }
})

例2:

  • 多个组件使用同一个挂载点,并动态切换【动态组件】
<div id="example">
  <button @click="change">切换页面</button>
  <component :is="currentView"></component>
</div>

var home = {template:'<div>我是主页</div>'};
var post = {template:'<div>我是提交页</div>'};
var archive = {template:'<div>我是存档页</div>'};
new Vue({
  el: '#example',
  components: {
    home,
    post,
    archive,
  },
  data:{
    index:0,
    arr:['home','post','archive'],
  },
  computed:{
    currentView(){
        return this.arr[this.index];
    }
  },
  methods:{
    change(){
      this.index = (++this.index)%3;
    }
  }
})

例2的另一种实现形式:

  • 直接绑定到组件对象上,位于data中,用数组表示
<div id="example">
  <button @click="change">切换页面</button>
  <component :is="currentView"></component>
</div>

new Vue({
  el: '#example',
  data:{
    index:0,
    arr:[
      {template:`<div>我是主页</div>`},
      {template:`<div>我是提交页</div>`},
      {template:`<div>我是存档页</div>`}
    ],
  },
  computed:{
    currentView(){
        return this.arr[this.index];
    }
  },
  methods:{
    change(){
      this.index = (++this.index)%3;
    }
  }
})

<keep-alive>标签

  • 包裹动态组件【含is】时,会缓存不活动的组件实例,而不是销毁它们
    • 失活的组件将会被缓存!
  • 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中
  • <transition> 相似

实例1:

  • 如果有多个条件性的子元素,<keep-alive> 要求同时只能有一个子元素被渲染
    • 子元素home
    • 子元素posts
    • 子元素archive
<div id="example">
  <button @click="change">切换页面</button>
  <keep-alive>
    <home v-if="index===0"></home>
    <posts v-else-if="index===1"></posts>
    <archive v-else></archive>  
  </keep-alive>
</div>

new Vue({
  el: '#example',
  components:{
    home:{template:`<div>我是主页</div>`},
    posts:{template:`<div>我是提交页</div>`},
    archive:{template:`<div>我是存档页</div>`},
  },
  data:{
    index:0,
  },
  methods:{
    change(){
      let len = Object.keys(this.$options.components).length;
      this.index = (++this.index) % len;
    }
  }
})

<keep-alive> 的属性【:include:exclude

用法:

  • include(包括) 和 exclude (不包括)属性允许组件有条件地缓存。
    • 首先检查组件自身的 name 选项,【匹配到后则缓存匹配的值】
    • 如果 name 选项不可用,则匹配它的局部注册名称(父组件 components 选项的键值)【匹配到后则缓存匹配的值】
  • (使用 v-bind)
<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
  <component :is="view"></component>
</keep-alive>

<!-- 正则表达式  -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>

<!-- Array -->
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

分析:

  • 这里是检查了自己的name属性,发现未找到
  • 再检查局部注册名称(父组件) components 选项的键值
    • 所以【include】只缓存home和archive,不缓存posts
<div id="example">
  <button @click="change">切换页面</button>
  <keep-alive include="home,archive">
    <component :is="currentView"></component> 
  </keep-alive>
</div>

new Vue({
  el: '#example',
  data:{
    index:0,
    arr:[
      {name:'home',template:`<div>我是主页</div>`},
      {name:'posts',template:`<div>我是提交页</div>`},
      {name:'archive',template:`<div>我是存档页</div>`}
    ],
  },
  computed:{
    currentView(){
        return this.arr[this.index];
    }
  },
  methods:{
    change(){
      var len = this.arr.length;
      this.index = (++this.index)% len;
    },
  }
})

<keep-alive> 的【activated()deactivated()】函数

用法:

  • <keep-alive> 树内的所有嵌套组件中触发
    • activated() 点击开始时
    • deactivated() 切换结束时

分析:

  • :is=“currentView”,函数在计算属性中定义
  • data的arr中存放模板
    • 注意:【activated()和deactivated()中的重写$emit函数,是vue自定义事件pass-data】
  • 当按顺序点击,轮到下标是 我是主页 的模板是触发自定义函数
    @pass-data,其参数则触发getData延迟(先显示$emit的第二个参数值,再消失"")
<div id="example">
  <button @click="change">切换页面</button>
  <keep-alive>
    <component :is="currentView" @pass-data="getData"></component>
  </keep-alive>
  <p>{{msg}}</p>
</div>

new Vue({
  el: '#example',
  data:{
    index:0,
    msg:'',
    arr:[
      {
        template:`<div>我是主页</div>`,
        activated(){
          this.$emit('pass-data','主页被添加');
        },
        deactivated(){
          this.$emit('pass-data','主页被移除');
        },
      },
      {template:`<div>我是提交页</div>`},
      {template:`<div>我是存档页</div>`}
    ],
  },
  computed:{
    currentView(){
        return this.arr[this.index];
    }
  },
  methods:{
    change(){
      var len = this.arr.length;
      this.index = (++this.index)% len;
    },
    getData(value){
      this.msg = value;
      setTimeout(()=>{
        this.msg = '';
      },500)
    }
  }
})

异步组件

  • 以一个工厂函数的方式定义你的组件,它会异步解析你的组件定义
  • 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染

核心:

  • 是第二个参数function (resolve, reject) {...}

实现:

  • resolve加载成功后,执行处理的逻辑
  • reject加载失败后,执行处理的逻辑

普通组件:

Vue.component('async-example', {
    template: `<div>this is a global component</div>`
})

异步组件:

Vue.component('async-example', function (resolve, reject) {
    // do some thing 处理其它逻辑,并在完成后向 `resolve` 回调传递组件定义
    resolve({
      template: '<div>I am async!</div>'
      // 组件定义的其它选项
    })

    // 或者调用reject回调表示失败
    reject({
        template: `<div>result is failed</div>`
    })
})

异步组件变成单文件.vue + webpack 的 code-splitting

【定义为异步加载的组件,在打包时,打包成单独js文件存储在static/js文件夹】

  • require

my-async-component.vue【变成单组件】

Vue.component('async-webpack-example', function (resolve) {
    // do some thing
    // 这个特殊的 `require` 语法将会告诉 webpack
    // 自动将你的构建代码切割成多个包,这些包
    // 会通过 Ajax 请求加载
    require(['./my-async-component'], resolve)
})
  • import会返回一个 Promise 对象
  • 可自定义异步加载状态【根据加载处理的状态来改变要渲染的组件】
    • loading
    • error
    • delay
    • timeout

async-webpack-example.vue【在组件引用这个组件】

情况1:全局注册组件,并异步加载

Vue.component('async-webpack-example',
    () => import('./my-async-component')
)

//-----------或者--------------------
Vue.component('async-webpack-example',
    () => ({
        component: import('./MyComponent.vue'),
        // 加载时使用的组件
        loading: LoadingComponent,
        // 加载失败时使用的组件
        error: ErrorComponent,
        // 展示加载时组件的延时时间。默认值是 200 (毫秒)
        delay: 200,
        // 如果提供了超时时间且组件加载也超时了,
        // 则使用加载失败时使用的组件。默认值是:`Infinity`
        timeout: 3000
    })
)

情况2:局部注册组件,并异步加载【根实例】

new Vue({
  components: {
    'async-webpack-example': () => import('./my-async-component')
  }
})

处理边界情况

处理边界情况之$root$parents$refs
【可替代将数据以 prop 的方式传入子组件】

  • $root$parents都能实现访问父组件的属性和方法
    • $root访问到的是它的根组件
    • $parents访问到的是最近一级的父组件
  • $refs只会在组件渲染完成之后生效,并且它们不是响应式的。
    • 避免在模板或计算属性中访问 $refs

子组件访问根实例【$root】

  • new Vue 根实例,其子组件可以通过 $root 属性进行访问
new Vue({
  data: {
    foo: 1
  },
  computed: {
    a: function () { /* ... */ }
  },
  methods: {
    b: function () { /* ... */ }
  }
})
// 获取根组件的数据
this.$root.foo
// 写入根组件的数据
this.$root.foo = 2
// 访问根组件的计算属性
this.$root.a
// 调用根组件的方法
this.$root.b()

子组件访问最近一级的父组件【$parents】

  • 最近一级的父组件,其子组件可以通过 $parents 属性进行访问
<div id="app">
    <root-obj></root-obj>
</div>
//子组件(是子子组件的父组件)
Vue.component('root-obj', {
    data() {
        return {

        }
    },
    template: `<div>
                    <button @click='getRoot'>子组件</button>
                    <child-component></child-component>
                </div>`,
    methods: {
        getRoot() {
            //得到自己
            console.log(this)]
            //得到var app = new Vue({})【根组件即这个的父组件】
            console.log(this.$parent)
            //得到var app = new Vue({})
            console.log(this.$root)
        }
    }
})
//子子组件
Vue.component('child-component', {
    data() {
        return {

        }
    },
    template: `<div>
                <button @click='getRoot'>子子组件</button>
                </div>`,
    methods: {
        getRoot() {
            //得到自己
            console.log(this)]
            //得到Vue.component('root-obj', {})
            console.log(this.$parent)
            //得到var app = new Vue({})
            console.log(this.$root)
        }
    }
})
//根组件
var app = new Vue({
    el: '#app',
    data: {
        msg: 'Root'
    }
})

父组件访问子组件实例【 ref$refs 最常用】

  • 最近一级的父组件,其子组件可以通过 $parents 属性进行访问
    • 避免在模板或计算属性中访问 $refs
    • 只会在组件渲染完成之后生效

实例1:vue-cli的单组件形式
首先子组件需添加ref="属性值",然后即可使用使用$refs.ref的属性值

父组件

<template>
    <base-alert ref="baseAlert"></base-alert>
    <div @click="clickMe">click me</div>
</template>

<script>
import BaseAlert from '@/components/BaseAlert'

export default {
    components: {
        BaseAlert
    },
    methods: {
        clickMe () {
          //popUp 方法在子组件中定义
          this.$refs.baseAlert.popUp()
        }
    }
}
</script>

<style scoped>
div {
  width: 20px;
  height: 20px;
  background: red;
  margin-top: 100px
}
</style>

子组件

<template>
  <div>
    <div>child component</div>
  </div>
</template>
<script>
export default {
  data () {
    return {
    }
  },
  methods: {
    popUp () {
      alert(abc)
    }
  }
}

</script>

实例2:

<div id="app">
  <button @click='refView'>通过ref访问子组件</button>
</div>
//子组件
Vue.component('base-input', {
    data() {
        return {
            msg: 'base-input'
        }
    },
    template: `<input type='text'/>`
})

//根实例
var app = new Vue({
    el: '#app',
    data: {
        msg: 'Root'
    },
    methods: {
        refView() {
            console.log(this.$refs.baseInput)
            this.$refs.baseInput.$el.focus()
        }
    }
})

依赖注入 provide选项inject选项

  • 把依赖注入看作一部分“大范围有效的 prop”
    • 明天再写,这里不太会
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值