Vue 基础之组件、组件传值、单项数据流、Non-props、父子组件通信、组件双向绑定、插槽、作用域插槽、动态组件、异步组件、provide 和 inject

一、Vue 基础之组件、组件传值、单项数据流、Non-props、父子组件通信、组件双向绑定、插槽、作用域插槽、动态组件、异步组件、provide 和 inject
  1. 组件的定义,组件具备复用性。全局组件,只要定义了,处处可以使用,性能不高,但是使用起来简单,名字建议,小写字母单词,中间用横线间隔。局部组件,定义了,要注册之后才能使用,性能比较高,使用起来有些麻烦,建议大写字母开头,驼峰命名。局部组件使用时,要做一个名字和组件间的映射对象,你不写映射,Vue 底层也会自动尝试帮你做映射,如下所示:
const Counter = {
  data() {
    return (
      count: 1
    )
  },
  template: `<div @click="count += 1">{{count}}</div>`
}

const HelloWorld = {
  template: `<div>hello world</div>`
}

const app = Vue.createApp({
  components: {
    // counter: Counter
    // 'hello-world': HelloWorld,
    Counter, HelloWorld
  },
  template: `
    <div>
      <hello-world />
      <counter />
    </div>
  `
});

// app.component('counter-parent', {
//   template: `<counter />`
// })

// app.component('counter', {
//  data() {
//    return {
//      count: 1
//    }
//  },
//  template: `<div @click="count += 1">{{count}}</div>` 
// })

const vm = app.mount('#root');
  1. vue 父子组件传值,父组件通过调用子组件的标签,通过标签上的属性向子组件传递一些值,子组件通过 props 接收对应父组件传递来的数据,然后在 props 接收好后就可以使用父组件的数据。静态传参不通过 v-bind,不加冒号,只能传递字符串。动态传参通过 v-bind 带入,加冒号,可以传递 String、Boolean、Array、Object、Function、Symbol 等等。动态传参比静态传参更加灵活,数据类型更多。在 props 传递的属性中,type 是传递的类型,required 是必填,default 是默认值,validator 是校验,如下所示:
const app = Vue.createApp({
  data() {
    return { num: 1234 }
  },
  template: `
    <div><test :content="num" /></div>
  `
});

app.component('test', {
  props: {
    content: {
      type: Number,
      validator: function(value) {
         return value < 1000;
      },
      default: function() {
        return 456;
      },
      required: true
    }
  },
  template: `<div>{{content}}</div>`
});
const vm = app.mount('#root');
  1. 单向数据流,子组件可以使用父组件传递过来的数据,但是绝对不能修改传递过来的数据,如下所示:
// v-bind="params"
// :content="params.content" :a="params.a" :b="params.b" :c="params.c"
const app = Vue.createApp({
  data() {
    return {
      num: 1
    }
  },
  template: `<div><counter :count="num" /></div>`
});

app.component('counter', {
  props: ['count'],
  data() {
    return {
      myCount: this.count
    }
  },
  template: `<div @click="myCount += 1">{{myCount}}</div>`
});
const vm = app.mount('#root');
  1. Non-props 属性,父组件向子组件传值,但是子组件不接收的情况,会把父组件传递过来的内容放到子组件最外层的 DOM 标签下,变成子组件最外层 DOM 标签的属性。Non-props 属性的应用场景,在组件的样式修改情况下。如果不想继承 non-props 属性,需要添加 inheritAttrs 属性为 false,如下所示:
const app = Vue.createApp({
  template: `<div><counter msg="hello" msg1="hello1" /></div>`
});

app.component('counter', {
  // inheritAttrs: false,
  mounted() {
    console.log(this.$attrs.msg);
  },
  template: `
    <div :msg="$attrs.msg">Counter</div>
    <div v-bind="$attrs">Counter</div>
    <div :msg1="$attrs.msg1"">Counter</div>
  `
});
const vm = app.mount('#root');
  1. 子组件给父组件传值,子组件通过 this.$emit 派发一个事件,并且也可以传递参数,父组件通过 v-on 监听对应的事件,并且绑定对应的事件处理。如果父子组件存在双向数据绑定的关系,可以可以使用 v-model。父组件使用 v-model 传递属性,子组件的 props 通过 modelValue 接收,通过 this.$emitupdate:modelValue 的形式派发事件,传递相应的参数。如果不想以 modelValue 的格式,那么传递的时候以加冒号别名的形式,如下所示:
const app = Vue.createApp({
  data() {
    return { count: 1 }
  },
  template: `<counter v-model="count" />`
});

app.component('counter', {
  props: ['modelValue'],
  methods: {
    handleClick() {
      this.$emit('update:modelValue', this.modelValue + 3);
    }
  },
  template: `<div @click="handleClick">{{modelValue}}</div>`
});
const vm = app.mount('#root');
  1. 父子组件存在双向数据绑定的关系,父组件通过 v-model 传递修饰符,在 v-model 后面加 .和对应的修饰符名字,修饰符通过 props 传递给子组件,子组件通过 props 中的 modelModifiers 接收,接收的时候可以设置默认值为空对象,在做后面的事件触发时可以根据修饰符做对应的处理,如下所示:
const app = Vue.createApp({
  data() {
    return {
      count: 'a',
    }
  },
  template: `<counter v-model.uppercase="count" />`
});

app.component('counter', {
  props: {
    'modelValue': String,
    'modelModifiers': {
      default: () => ({})
    }
  },
  methods: {
    handleClick() {
      let newValue = this.modelValue + 'b';
      if (this.modelModifiers.uppercase) {
        newValue = newValue.toUppercase();
      }
      this.$emit('update:modelValue', newValue);
    },
  },
  template: `<div @click="handleClick">{{modelValue}}</div>`
});
const vm = app.mount('#root');
  1. slot 插槽,如果父组件想往子组件中传递 DOM 节点或元素标签的时候,没必要通过属性方式去传,直接把元素写在标签中间,子组件通过 slot 调用传递过来的内容。slot 中使用的数据,作用域的问题,父模版里调用的数据属性,使用的都是父模版里的数据。子模版里调用的数据属性,使用的都是子模版里的数据。具名插槽,如下所示:
const app = Vue.createApp({
  template: `
    <layout>
      <template v-slot:header>
        <div>header</div>
      </template>
      <template v-slot:footer>
        <div>footer</div>
      </template>
    </layout>
  `
});

app.component('layout', {
  template: `
    <div>
      <slot name="header"></slot>
      <div>content</div>
      <slot name="footer"></slot>
    </div>
  `
});
const vm = app.mount('#root');
  1. 作用域插槽,如下所示:
const app = Vue.createApp({
  template: `
    <list v-slot="slotProps">
      <div>{{slotProps.item}}</div>
    </list>
  `
});

app.components('list', {
  data() { return { list: [1,2,3]}},
  template: `
    <div><slot v-for="item in list" :item="item" /></div>
  `
});
const vm = app.mount('#root');
  1. 动态组件,根据数据的变化,结合 component 这个标签,来随时动态切换组件的实现。keep-alive,当动态组件第一次渲染的时候,会把里面输入的状态、变更的情况都记录下来,当再次用这个组件的时候,会从缓存中将之前的数据拿出来填充上,具有缓存的特性,所以动态组件有时候会和 keep-alive 一起使用。异步组件,是异步执行某些组件的逻辑,这叫做异步组件,如下所示:
const app = Vue.createApp({
  template: `
    <div>
      <common-item />
      <async-common-item />
    </div>
  `
});

app.component('common-item', {
  template: `<div>hello world</div>`
});

app.component('async-common-item', Vue.defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        template: `<div>this is an async component</div>`
      })
    }, 4000)
  })
}));
const vm = app.mount('#root');
  1. v-once 让某个元素标签只渲染一次,ref 实际上是获取 DOM 节点或组件引用的一个语法。如果涉及多层组件传值,可以使用 provide / injectprovide 提供数据,inject 跨越多层组件注入使用,如下所示:
const app = Vue.createApp({
  data() {
    return { 
      count: 1 
    }
  },
  provide() {
    return {
      count: this.count
    }
  },
  template: `
    <div>
      <child :count="count" />
      <button @click="count += 1">Add</button>
    </div>
  `
});

app.component('child', {
  template: `<child-child />`
});

app.component('child-child', {
  inject: ['count'],
  template: `<div>{{count}}</div>`
});
const vm = app.mount('#root');
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值