0
点赞
收藏
分享

微信扫一扫

Vuejs装饰器风格开发教程(模板引用、依赖注入、数据双向绑定)

琛彤麻麻 2023-08-18 阅读 42

模板引用

在类组件中组件的引用(ref)同样是一个特殊的类属性,这个类属性是由 @Ref 装饰器描述的一个只读属性。

<script lang="ts">
import { Component, Ref, Vue } from 'vue-facing-decorator';

@Component({
  name: 'MyComponent',
})
export default class MyComponent extends Vue{

  @Ref
  readonly refEl!: HTMLDivElement;

  mounted() {
    console.log(this.refEl.innerText);
  }
}
</script>

<template>
  <div ref="refEl">Hello World</div>
</template>

[^注]: 在组件挂在后即可通过声明的 refEl 属性正常的 div 中的文本内容了。

依赖注入

依赖注入的目的是便于上层组件提供数据的便捷,主要出现在多层级间进行数据传递。Inject 作用在获取数据的组件,同时还要由 Provide 作用在上层组件为其提供数据。

在类组件中可以通过 @Inject 装饰器来描述一个类属性为注入的数据,在 03类组件详解中 有讲到可以通过 @Component 装饰器的选项 provide 来在上层组件进行数据提供,现在应该是获取上层组件提供的数据了。

在顶层组件的 @Component 装饰器增加选项 provide,provide 为一个函数是为了接收一组对象,且对象中的指定数据可能为计算属性,因为只有计算属性快照发生变化后,下层组件中获取的数据才会发生变化:

<script lang="ts">
  import { computed } from 'vue';
  import CardWapper from './components/CardWapper.vue';
  import { Component, Vue } from 'vue-facing-decorator';

  @Component({
    components: {
      CardWapper,
    },
    provide() {
        return {
          title: computed(() => this.title),
          footers: this.footers,
        }
    }
  })
  export default class App extends Vue {
    title = '相册集';

    footers = [
      {
        name: 'copy',
        link: 'http://www.baidu.com',
      },
      {
        name: 'jump',
        link: 'https://juejin.cn',
      },
    ];

    update() {
      this.title = '相册集' + Date.now();
    }

  }
</script>

<template>
  <div>
    <button @click="update">更新标题</button>
    <CardWapper></CardWapper>
  </div>
</template>

CardWapper 中添加 Card 组件,不做多余的配置:

<script lang="ts">
import Card from './Card.vue';
import { Component, Vue } from 'vue-facing-decorator';
@Component({
  name: 'CardWapper',
  components: {
      Card,
  },
})
export default class CardWapper extends Vue {}
</script>

<template>
  <Card></Card>
</template>

Card 组件中使用 @Inject 获取已经注入的数据,from 参数与提供时指定的一致,如果 @Inject 所描述的类属性与提供时的名称一致可忽略 from 参数:

<script lang="ts">
  import { Component, Inject, Vue } from 'vue-facing-decorator';

  @Component({
    name: 'Card',
  })
  export default class Card extends Vue {
    @Inject({
      from: "title",
    })
    title!: string;

    @Inject({
      from: "cover",
      default:
        'https://www.bing.com/th?id=OHR.PandiZucchero_ZH-CN9833521922_1920x1080.webp',
    })
    cover!: string;

    @Inject({
      from: "footers",
    })
    footers!: any;
  }
</script>

<template>
  <div class="container">
    <div class="title">{{ title }}</div>
    <img :src="cover" />
    <div class="footer">
      <button v-for="footer in footers">{{ footer.name }}</button>
    </div>
  </div>
</template>

<style scoped>
  .container {
    text-align: left;
    width: 240px;
    background-color: #fff;
    border-radius: 10px;
    box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
    padding: 20px;
    margin: 20px;
    transition: 0.2s;
  }

  .container:hover {
    transform: scale(1.01);
    box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
  }

  .container .title {
    font-size: 18px;
    font-weight: 600;
    border-bottom: 1px solid rgba(0, 0, 0, 0.3);
  }

  .container img {
    width: 240px;
    height: 135px;
    border-radius: 5px;
    margin-top: 10px;
  }

  .container .footer {
    display: flex;
    gap: 10px;
    justify-content: right;
  }
</style>

[^注]: 到 3.0.0 版本为止,案例中发现在下层组件获取的数据会被增加多余的双引号,在 3.0.1 增加的 @Provide 装饰器我似乎还是没明白如何实现响应式。

数据双向绑定

双向绑定的作用就是保证输入的内容与声明的响应式变量可以实时同步,在 Vuejs 中双向绑定常体现在表单的处理上,如:inputselecttextarea

在自定义组件中实现双向绑定必须要声明自定义组件的属性 props 和对应处理的事件 emits,下面在摘自 Vuejs 网站的部分代码:

<script>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue']
}
</script>

<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>
<CustomInput v-model="searchText" />

在类组件中可以通过 @Model 装饰器来替换上面这段比较繁琐的代码:

<script lang="ts">
import { Component, Model, Vue } from 'vue-facing-decorator'

@Component
export default class CustomInput extends Vue {
  @Model
  inputValue!: string = '';
}
</script>

<template>
  Input:<input v-model="inputValue" >
</template>
<CustomInput v-model:modelValue="text"></CustomInput>

@Model 装饰器提供与 Prop 几乎一样的选项支持,额外的 name 选项默认的值是 modelValue,在对其进行修改时要注意类组件中属性声明禁止重复。

举报

相关推荐

0 条评论