【前端进阶】玩转 VUE 组件式开发

1.整体目标

  • 了解组件开发的整体流程
  • 掌握组件事件和标签事件的区别
  • 掌握在组建上使用 v-model 的方式

2.Button 组件开发

2.1 确定组件API

属性
属性名说明类型默认值
type设置按钮类型,可选值为 primary danger 或者不设Stringdefault
size设置按钮大小,可选值为small large 或者不设置Stringdefault
事件
事件名称说明回调参数
click按钮点击事件(event)=>void

2.2 编写测试基础Button

组件有很多的功能,但是这些功能都是一个最原始的组件逐渐拓展而来的,所以我们先完成一个最基础的button组件,然后逐渐增加功能

// components/button/index.vue
<template>
  <button class="btn-default">
    <slot></slot>
  </button>
</template>

<script>
export default {
  name: "HButton",
};
</script>
<!-- 开发组件的时候 scoped 是必须要加的 不能影响其他的样式 !-->
<style scoped lang="less">
.btn-default {
  line-height: 1.499;
  position: relative;
  display: inline-block;
  font-weight: 400;
  white-space: nowrap;
  text-align: center;
  background-image: none;
  box-shadow: 0.5px 2px 0 rgba(0, 0, 0, 0.05);
  cursor: pointer;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  transition: all 0.3s cubic-bezier(0.6, 0.04, 0.3, 1);
  touch-action: manipulation;
  padding: 5px 10px;
  font-size: 14px;
  border-radius: 4px;
  color: rgba(0 0 0 / 0.65);
  //outline: none;
  border: 1px solid #ddd;
  background-color: #fff;
  &:focus {
    color: rgab(0, 0, 0, 1);
    box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
  }
  &:hover {
    color: rgba(133, 13, 3, 0.31);
  }
}
</style>

2.3 完成tpye配置

1.准备对应的class类

// primary
.btn-primary {
  color: #fff;
  background-color: #1890ff;
  border-color: #1890ff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
}

// danger
.btn-danger {
  color: #fff;
  background-color: #ff4d4f;
  border-color: #ff4d4f;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
}
2.编写props
setup(props) {
  console.log(props);
  let activeClass = computed(() => {
    return "btn-" + props.type;
  });
  return {
    activeClass,
  };
},

2.4 完成size的配置

1.准备对应的class 类
 //size :small
.btn-size-small {
  padding: 4px 8px;
  font-size: 12px;
}
 //size :large
.btn-size-large {
  padding: 6px 12px;
  font-size: 16px;
}
2.编写props
 props: {
    type: {
      type: String,
      default: "default",
    },
    size: {
      type: String,
      default: "default",
      // 参数校验
      validator: function (value) {
        // value 代表当前传来的值
        //console.log(value);
        // 对传入的参数做校验 满足条件返回true 不满足就返回false
        // 如果传入的参数不在可选参数的列表中 给出用户提示 告诉哪个参数传错了
        // 如果传入的参数 在可选的参数列表中 直接通过 不会报错
        const sizeList = ["small", "large", "default"];
        return sizeList.includes(value);
      },
    },
setup(props) {
  console.log(props);
  let typeClass = computed(() => {
    return "btn-type-" + props.type;
  });
  let sizeClass = computed(() => {
    return "btn-size-" + props.size;
  });
  return {
    typeClass,
    sizeClass,
  };
},

2.5 完成事件绑定

// 父组件
</template>
	<Button @click="clickHandler">click me</Button>
</template>
<script>
setup() {
    const clickHandler = (e) => {
      console.log("click me", e.target);
    };
    return {
      clickHandler,
    };
  },
</script>

注意:

  • vue2 中 事件如果写到原生支持的标签身上会被直接识别为原生事件, <button @click='handler'></button>
  • 事件如果写到自定义组件身上 默认状态会被识别为自定义事件 <Button @click='handler'></Button>
    1. 增加 .native 修饰符 可以让vue 系统帮助我们把事件绑定成为浏览器支持的原生事件
    2. 就当成自定义事件识别 然后按照父子组件通信的手段 通过子组件内事件触发 然后调用$emit 方法触发即可
  • 在vue3 中不会有这种问题 内置的事件就是内置的事件 除了内置的事件都会被当作自定义事件进行解析

2.6 总结

  • 编写组件时 应该API先行 先确定组件该如何给用户使用 再根据API编写逻辑
  • props 的名称应该具备语义化,类型应该规范,并且可以添加自定义校验
  • 组件上绑定的类似于原生的事件 默认是不会被识别的,需要额外处理
  • 组件有一些设计需要整体把控,比如props 与对应类名的匹配

3. Editor编辑器组件开发

3.1 确定基础API

指令名说明类型默认值
v-model提供编辑器数据的双向绑定String

3.2 编写测试基础Editor

Editor/index.js

<template>
  <div style="border: 1px solid #ccc">
    <Toolbar
      style="border-bottom: 1px solid #ccc"
      :editor="editorRef"
      :defaultConfig="toolbarConfig"
      :mode="mode"
    />
    <Editor
      style="height: 500px; overflow-y: hidden"
      v-model="valueHtml"
      :defaultConfig="editorConfig"
      :mode="mode"
      @onCreated="handleCreated"
    />
  </div>
</template>

<script>
import "@wangeditor/editor/dist/css/style.css"; // 引入 css

import { onBeforeUnmount, ref, shallowRef, onMounted } from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";

export default {
  components: { Editor, Toolbar },
  name: "costume-editor",
  setup() {
    // 编辑器实例,必须用 shallowRef
    const editorRef = shallowRef();

    // 内容 HTML
    const valueHtml = ref("<p>hello</p>");

    // 模拟 ajax 异步获取内容
    onMounted(() => {
      console.log(valueHtml);
      console.log(editorRef);
      setTimeout(() => {
        valueHtml.value = "<p>模拟 Ajax 异步设置内容</p>";
      }, 1500);
    });

    const toolbarConfig = {};
    const editorConfig = { placeholder: "请输入内容..." };

    // 组件销毁时,也及时销毁编辑器
    onBeforeUnmount(() => {
      const editor = editorRef.value;
      if (editor == null) return;
      editor.destroy();
    });

    const handleCreated = (editor) => {
      editorRef.value = editor; // 记录 editor 实例,重要!
    };

    return {
      editorRef,
      valueHtml,
      mode: "simple", // 或 'simple'
      toolbarConfig,
      editorConfig,
      handleCreated,
    };
  },
};
</script>

<style scoped></style>

3.3 完成v-model 双向绑定

//vue2 中 v-model 语法唐
<!--
    1. 编辑器组件可以接收我传入的数据 并且可以显示到编辑器内部 实现数据的回显
    2. 一旦编辑器中进行内容编辑之后 绑定的content 属性 也可以得到修改 变成编辑器中最新的值

    体现出来的就是双向数据绑定的特性

    实现步骤:
    1.实现回显
    v-model 一旦写到一个组件身上 默认情况下 相当于传入了名为value 的自定属性 以及名为input的自定义事件
    v-model 其实是一个语法糖 可以写一次完成两件事情

    2.编辑器一旦编辑内容就把绑定的content属性修改掉
    难点1 如果知道内容已经遍及了 三方插件提供了方法
    难点2 如果拿到最新的编辑内容然后传出来给content(子传父)

 -->
// vue 2
<Editor v-model="content"></Editor>
// 相当于
<Editor :value="content" @input="content = $event" />
// Editor 组件
<template>
  <div>
    <input type="content" :value="value" @input="$emit('input',$event.target.value)">
  </div>
</template>

<script>
export default {
  props: {
    content: String,  // 默认接收一个名为 content 的 prop
  }
}
</script>
// vue3 中 v-model

<template>
  <div>
    <input
      type="text"
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"  // 事件名改为 update:modelValue
    />
  </div>
</template>

<script>
export default {
  props: {
    modelValue: String, // 默认 prop 从 value 改为 modelValue
  },
};
</script>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

貂蝉的腿毛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值