前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vue2你该知道的一切(下)

vue2你该知道的一切(下)

作者头像
kai666666
发布2024-07-11 18:54:17
1020
发布2024-07-11 18:54:17
举报
文章被收录于专栏:橙光笔记

本章继续回顾Vue相关的知识,主要针对组件这块,基础部分请看上一章

组件基础

简单的组件:

代码语言:javascript
复制
<div id="app">
  <custom-button></custom-button>
</div>
<script>
  // 自定义组件
  const CustomButton = {
    template: '<button>Custom button</button>'
  };

  new Vue({
    el: '#app',
    components: {
      CustomButton
    }
  });
</script>

上面的组件需要在components中引入,当然也可以定义一个全局的组件:

代码语言:javascript
复制
Vue.component('custom-button', {
  template: '<button>Custom button</button>'
});

上面组件只有一个template属性,一般的组件还有data、方法、计算属性等。这里需要注意的是组件的data需要是一个方法,并且返回一个对象,而Vue实例的data是一个对象,如果组件的data是一个对象的话,那么多个组件将会使用一份数据,这样所有组件数据都是一样的,某个组件修改数据会影响到其他的同类组件。

代码语言:javascript
复制
Vue.component('positive-numbers', {
  template: '<p>{{ positiveNumbers.length }} positive numbers</p>',
  data() { // 组件中这里需要是函数
    return {
      numbers: [-5, 0, 2, -1, 1, 0.5]
    };
  },
  computed: {
    positiveNumbers() {
      return this.numbers.filter((number) => number >= 0);
    }
  }
});

Props

组件的Props可以声明父组件要传递到子组件的数据:

代码语言:javascript
复制
<div id="app">
  <color-preview color="red"></color-preview>
  <color-preview color="blue"></color-preview>
</div>
<script>
  Vue.component('color-preview', {
    template: '<div class="color-preview" :style="style"></div>',
    props: ['color'],
    computed: {
      style() {
        return { backgroundColor: this.color };
      }
    }
  });

  new Vue({
    el: '#app'
  });
</script>

props可以添加校验和默认值以及是否必须,校验失败在开发环境会报错:

代码语言:javascript
复制
Vue.component('price-display', {
  props: {
    price: {
      type: Number,
      required: true,
      validator(value) {
        return value >= 0;
      }
    },
    num: {
      type: Number,
      required: true
    },
    unit: {
      type: String,
      default: '$'
    }
  }
});

组件props的大小写

模板中组件的props如果是带横线的属性,最后在组件内部将会自动转化为驼峰形式,如下

代码语言:javascript
复制
<div id="app">
  <price-display percentage-discount="20"></price-display>
</div>
<script>
  Vue.component('price-display', {
    props: {
      percentageDiscount: Number
    }
  });

  new Vue({
    el: '#app'
  });
</script>

这里需要注意一点percentage-discount="20"它的值最后是字符串的’20’而不是数字的20,所以上面代码会报错,如果要是数字的则需要:percentage-discount="20",同样的Boolean类型的也一样。

sync操作符

子组件中不建议直接修改父组件传下来的props,通常使用子组件的$emit方法来修改告诉父组件要修改值。某些情况下可以使用aync操作符来简化,赋值操作。

代码语言:javascript
复制
<count-from-number :number.sync="numberToDisplay"/>

组件定义:

代码语言:javascript
复制
Vue.component('count-from-number', {
  template: '<p>The number is {{ number }}</p>',
  props: {
    number: {
      type: Number,
      required: true
    }
  },
  mounted() {
    setInterval(() => {
      this.$emit('updated:number', this.number + 1);
    }, 1000);
  }
});

实际上sync操作符只是一个语法糖,上面使用sync操作符的代码等同于:

代码语言:javascript
复制
<count-from-number
  :number.sync="numberToDisplay"
  @update:number="val => numberToDispaly = val"
  />

自定义组件的v-model

假设现在需要写一个只能输入小写字母的组件input-username,它需要支持v-model:

代码语言:javascript
复制
<input-username
  v-model="username"
  />

上述代码等同于:

代码语言:javascript
复制
<input-username
  :value="username"
  @input="value => username = value"
  />

所以要使得自定义组件支持v-model可以这样写:

代码语言:javascript
复制
Vue.component('input-username', {
  template: '<input type="text" :value="value" @input="handleInput">',
  props: {
    value: {
      type: String,
      required: true
    }
  },
  methods: {
    handleInput(e) {
      const value = e.taret.value.toLowerCase();

      // If valeu was changed, update it on the input too
      if (value !== e.target.value) {
        e.target.value = value;
      }

      this.$emit('input', value);
    }
  }
});

插槽slot

简单使用:

代码语言:javascript
复制
Vue.component('custom-button', {
  template: '<button class="custom-button"><slot></slot></button>'
});

上面定义了一个custom-button的组件,则组件中间的部分将会给到插槽的位置:

代码语言:javascript
复制
<custom-button>Press me!</custom-button>

渲染后:

代码语言:javascript
复制
<button class="custom-button">Press me!</button>

插槽也可以给默认内容,只要下载slot标签中间:

代码语言:javascript
复制
Vue.component('custom-button', {
  template: `<button class="custom-button">
    <slot><span class="default-text">Default button text</span></slot>
  </button>`
});

这是如果自定义组件没有内容的时候将会使用默认内容,如:

代码语言:javascript
复制
<custom-button></custom-button>

渲染后:

代码语言:javascript
复制
<button class="custom-button">
  <span class="default-text">Default button text</span>
</button>

具名插槽就是给插槽起一个名字,如下面是blog-post组件的模板,其中<slot name="header"></slot>就是一个具名插槽,

代码语言:javascript
复制
<section class="blog-post">
  <header>
    <slot name="header"></slot>
    <p>Post by {{ author.name }}</p>
  </header>

  <main>
    <slot></slot>
  </main>
</section>

使用方式也很简单:

代码语言:javascript
复制
<blog-post :author="author">
  <h2 slot="header">Blog post title</h2>

  <p>Blog post content</p>

  <p>More blog post content</p>
</blog-post>

最终渲染的结果是:

代码语言:javascript
复制
<section class="blog-post">
  <header>
    <h2>Blog post title</h2>
    <p>Post by Callum Macrae</p>
  </header>

  <main>
    <p>Blog post content</p>

    <p>More blog post content</p>
  </main>
</section>

作用域插槽,组件的插槽可以向外面暴露数据:

代码语言:javascript
复制
Vue.component('user-data', {
  template: '<div class="user"><slot :user="user"></slot></div>',
  data: () => ({
    user: { name: 123 },
  }),
});

new Vue({
  el: '#app',
  data:{
    username:'123'
  },
  template: `<user-data v-slot:default="aaa">
      <p >User name: {{ aaa.user.name }}</p>
    </user-data>`
});

上面相当于给defailt作用域的值定义为aaa变量,aaa.user就能获取到插槽的user属性了。当然默认插槽的也可以简写:v-slot="aaa"

Mixin

mixin的简单使用:

代码语言:javascript
复制
const loggingMixin = {
  created() {
    console.log('Logged from mixin');
  }
};

Vue.component('example-component', {
  mixins: [loggingMixin],
  created() {
    console.log('Logged from component');
  }
});

当组件被创建后先后打印:Logged from mixinLogged from component。说白了mixin对象就是一个普通的JavaScript对象,它可以混入属性、方法、生命周期等,其中属性和方法如果组件中也有同名的则组件中的会覆盖mixin中的,但是生命周期都会执行。

vue-loader的使用

当使用vue-loader了以后就可以创建.vue文件了。

之前的组件书写形式是:

代码语言:javascript
复制
Vue.component('display-number', {
  template: '<p>The number is {{ number }}</p>',
  props: {
    number: {
      type: Number,
      required: true
    }
  }
});

.vue文件组件的书写形式是:

代码语言:javascript
复制
<template>
  <p>The number is {{ number }}</p>
</template>

<script>
  export default {
    props: {
      number: {
        type: Number,
        required: true
      }
    }
  };
</script>

代码更加之目了然了,组件的引用如下:

代码语言:javascript
复制
<div id="app">
  <display-number :number="4"></display-number>
</div>
<script>
  import DisplayNumber from './components/display-number.vue';

  new Vue({
    el: '#app',
    components: {
      DisplayNumber
    }
  });
</script>

非prop属性

vue对非prop属性的处理是放在组件的外层上,并覆盖原有的。对于class和style则会合并。

代码语言:javascript
复制
<div id="app">
  <custom-button type="submit">Click me!</custom-button>
</div>
<script>
  const CustomButton = {
    template: '<button type="button"><slot></slot></button>'
  };

  new Vue({
    el: '#app',
    components: {
      CustomButton
    }
  });
</script>

最后渲染为:

代码语言:javascript
复制
<button type="submit">Click me!</button>

可以使用this.$attr获取所有的非props属性。

render方法

上面的例子中都是使用template来定义组件的,实际上还可以写render函数来定义组件。假设有一个组件:

代码语言:javascript
复制
const CustomButton = {
  data: () => ({
    counter: 0,
  }),
  template: `<div>
    <button v-on:click="counter++">Click to increase counter</button>
    <p>You've clicked the button {{ counter }}</p> times.
  </div>`
};

使用render定义如下:

代码语言:javascript
复制
const CustomButton = {
  data: () => ({
    counter: 0,
  }),
  render(createElement) {
    return createElement(
      'div',
      [
        createElement(
        'button',
          {
            on: {
              click: () => this.counter++,
            }
          },
          'Click to increase counter'
        ),
        createElement(
          'p',
          `You've clicked the button ${this.counter} times`
        )
      ]
    );
  }
};

上述代码是不是很难理解?render中代码的编写通常是由JSX来生成的,项目中使用babel-plugin-transform-vue-jsx插件可以把JSX转换成类似于上述的函数内容。上述代码如果使用了JSX编写如下,是不是React很像?

代码语言:javascript
复制
const CustomButton = {
  data: () => ({
    counter: 0,
  }),
  methods: {
    clickHandler() {
      this.counter++
    }
  },
  render() {
    return (
      <div>
        <button onClick={this.clickHandler}>Click to increase counter</button>
        <p>You've clicked the button {counter} times</p>
      </div>
    );
  }
};

如果render和template同时出现,那么优先会使用render。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 组件基础
  • Props
  • 组件props的大小写
  • sync操作符
  • 自定义组件的v-model
  • 插槽slot
  • Mixin
  • vue-loader的使用
  • 非prop属性
  • render方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档