首页IT科技vue.js封装公共组件(Vue组件化开发–公共组件的封装)

vue.js封装公共组件(Vue组件化开发–公共组件的封装)

时间2025-08-04 16:08:25分类IT科技浏览5895
导读:目录...

目录

为什么要封装组件

应用场景

vue自己封装组件(局部              、全局) 

Vue组件的三要素

①全局组件

1)方式:

 2)示例:

②局部组件

1)方式:

2)示例:

命名规范:(注意)

脚手架vue-cli中的组件

父传子(props)

通过 $on 传递父组件方法

$parent获取父组件然后使用父组件中的数据(不推荐)

通过$emit传递父组件数据 (推荐) 

refs获取

组件样式修改 样式穿透 

插件使用:slot

为什么要封装组件

用vue开发的项目              ,都是采用组件化的思想开发的              。

一般在搭建项目的时候                     ,会创建一个views目录                     、一个commen目录和一个feature目录                     。

views目录中放页面级的组件 commen中放公共组件(如:head(公共头组件)       ,foot(公共底部组件)等) feature目录内放功能组件(如:swiper(轮播功能组件)              ,tabbar(切换功能组件)       、list(上拉加载更多功能组件))

组件可以提升整个项目的开发效率       。能够把页面抽象成多个相对独立的模块                     ,解决了我们传统项目开发:效率低              、难维护                     、复用性低等问题              。

使用组件的好处

组件是可以复用性的 易于维护 有封装性       ,易于使用 大型项目中降低组件之间重复性

 

应用场景

项目中很多模块经常会复用:侧边导航组件       、分页       、文件下载                     、项目中常用的 echarts图表的封装(比如折线图              、柱状图等)       ,或者一些后台管理       、菜单管理中很多可复用组件                     ,表单之类的                     。

封装组件需要考虑复用性:

预留插槽slot, 多次调用如果 子组件视图结构不一样那么就要在子组件template预留好插槽(单个插槽                     、具名插槽              ,作用域插槽) 考虑到数据传递       ,定义props 组件接收父组件传递的数据                     ,同时需要注意单向数据流              ,props不能直接修改,$emit自定义事件                     ,父组件修改 业务逻辑不要在子组件中处理                     ,子组件在不同父组件中调用时,业务处理代码不同              ,切记不要直接在子组件中处理业务                     ,应该子组件 $emit自定义事件       ,将数据传递给父组件              ,父组件处理业务       。

vue自己封装组件(局部              、全局) 

封闭性:当在组件定义好外部不能修改;

开放性:将动态内容和组件通讯方式进行传递数据保证组件可扩展性;

Vue组件的三要素

1. props参数

2. slot定制插槽

3. event自定义事件

①全局组件

1)方式:

可以在main.js中注册成全局组件       。

import Bread from @/layout/bread;// 引入 Vue.component("Bread",Bread);// 全局注册

 2)示例:

引用全局组件my-header

<body> <div id="main1"> <!-- 正常模板解析的时候                     ,不会将自定义标签解读出来       ,而是将自己定义组件里的参数解读出来       ,也就是下面template中的h1标签 --> <my-header></my-header> </div> <div id="main2"> <!-- 自定义组件具有复用性 --> <my-header></my-header> </div> <div id="main3"> <my-header></my-header> </div> </body>

注册全局组件my-header

//全局组件:在任何地方                     ,任何方式              ,任何地点都可以使用的标签组件 vue.component("my-header", { // h1标签是我们在自定义主键里面写的参数的标签 template: <h1>标题{{msg}}</h1>, data(){ return {msg:100} } }) new Vue({ el: #main }); new Vue({ el: #main2 }); new Vue({ el: #main3 });

②局部组件

1)方式:

新建一个vue文件 在需要使用的组件里引入:import UploadIDCard from “./fillInfo/upIDCard              ”; 注册 components: { Position: () => import("@/layout/position"), UploadIDCard },

注册后       ,UploadIDCard可以当做一个标签使用                     。(局部组件)              。

2)示例:

局部组件:只是在我们规定的范围之内才会生效       。

<body> <div id="main"> <my-header></my-header> <my-header></my-header> </div> </body> new Vue({ el: #main, components: { "my-header": { template: <h1>标题{{vue}}</h1> } } })

命名规范:(注意

当使用 kebab-case(中划线命名) 定义一个组件时                     ,你也必须在引用这个自定义元素时使用 kebab-case              ,例如<my-component-name> 当使用 PascalCase (驼峰式命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用                     。 也就是说<my-component-name>和<MyComponentName> 都是可接受的              。注意                     ,尽管如此                     ,直接在 DOM(即非字符串的模板) 中使用时只有kebab-case 是有效的。 总结:中划线命名在使用时必须保持命名一致,而驼峰命名在使用时既可以用驼峰也可以用中划线                     。 //中划线 使用语法: <my-component-name>` Vue.component(my-component-name, { /* ... */ }) //驼峰 使用语法:<my-component-name> `和` <MyComponentName>`都可以 Vue.component(MyComponentName, { /* ... */ })

脚手架vue-cli中的组件

组件之间的数据传递 我们一般通过脚手架vue-cli开发项目              ,每个 .vue单文件就是一个组件                     。在父组件中使用import 导入一个子组件                     ,并在components中注册子组件       ,子组件需要数据              ,可以在props中接受定义。而子组件修改好数据后                     ,想把数据传递给父组件              。可以采用$emit方法触发自定义事件传递参数                     。

父传子(props)

prop 的定义应该尽量详细       ,至少需要指定其类型

父组件通过属性的形式向子组件传递数据       ,子组件使用props接收数据                     ,但是通用组件的应用场景比较复杂              ,对 props 传递的参数应该添加一些验证规则       ,即:

props: { propA: Number, // 基础类型检测 (`null` 意思是任何类型都可以) propB: [String, Number], // 多种类型 propC: { // 必传且是字符串 type: String, required: true }, propD: { // 数字                     ,有默认值 type: Number, default: 100 }, propE: { // 数组/对象的默认值应当由一个工厂函数返回 type: Object, default: function () { return { message: hello } } }, propF: { // 自定义验证函数 validator: function (value) { return value > 10 } } }

由于存在一个单项数据流的问题              ,父组件传递给子组件的数据不要直接修改,因为会将父组件中的数据也修改                     ,当这个数据也传入其他组件的时候就会出问题了       。vue2.5已经针对 props 做出优化                     ,这个问题已经不存在了 如果一定需要有这样的操作,可以这么写:

let copyData = JSON.parse(JSON.stringify(this.data))

为什么不直接写 let myData = this.data 呢? 因为直接赋值              ,对于对象和数组而言只是浅拷贝                     ,指向的是同一个内存地址       ,其中一个改变另一个也会改变              。而通过 JSON颠倒转换之后              ,实现了深拷贝                     ,则可以互不影响                     。

<!-- 父组件 --> <template> <div> <my-child :parentMessage="parentMessage"></my-child> </div> </template> <script> import MyChild from @components/common/MyChild export default { components: { MyChild }, data() { return { parentMessage: "我是来自父组件的消息" } } } </script> <!-- 子组件 --> <template> <div> <span>{{ parentMessage }}</span> </div> </template> <script> export default { props: { parentMessage: { type: String, default: 默认显示的信息 // require: true // 必填 } } } </script>

通过 $on 传递父组件方法

通过$on传递父组件方法是组件通信中常用的方法传递方式       。它可以与通过props传递方法达到相同的效果       。相比于props传递function,它更加的直观和显示的表现出了调用关系

<!-- 父组件 --> <template> <div> <my-child @childEvent="parentMethod"></my-child> </div> </template> <script> import MyChild from @components/common/MyChild export default { components: { MyChild, }, data() { return { parentMessage: 我是来自父组件的消息, } }, methods: { parentMethod() { alert(this.parentMessage) } } } </script> <!-- 子组件 --> <template> <div> <h3>子组件</h3> </div> </template> <script> export default{ mounted() { this.$emit(childEvent) } } </script>

$parent获取父组件然后使用父组件中的数据(不推荐)

准确来说这种方式并不属于数据的传递而是一种主动的查找

                    。父组件并没有主动的传递数据给子组件       ,而是子组件通过与父组件的关联关系       ,获取了父组件的数据              。

该方法虽然能实现获取父组件中的数据但是不推荐这种方式                     ,因为vue提倡单向数据流              ,只有父组件交给子组件的数据子组件才有使用的权限       ,不允许子组件私自获取父组件的数据进行使用       。在父与子的关系中子应当是处于一种被动关系

通过$emit传递父组件数据 (推荐) 

子组件向父组件中传递数据

子组件向父组件中传递数据:触发父组件方法,并传递参数data到父组件

与父组件到子组件通讯中的$on配套使用                     ,可以向父组件中触发的方法传递参数供父组件使用

<!-- 父组件 --> <template> <div> <my-child @childEvent="parentMethod"></my-child> </div> </template> <script> import MyChild from @components/common/MyChild export default { components: { MyChild }, data() { return { parentMessage: 我是来自父组件的消息 } }, methods: { parentMethod({ name, age }) { console.log(this.parentMessage, name, age) } } } </script> <!-- 子组件 --> <template> <div> <h3>子组件</h3> </div> </template> <script> export default { mounted() { this.$emit(childEvent, { name: zhangsan, age: 10 }) } } </script>

refs获取

可以通过在子组件添加ref属性              ,然后可以通过ref属性名称获取到子组件的实例                     。准确来说这种方式和this.$parent

一样并不属于数据的传递而是一种主动的查找              。

尽量避免使用这种方式。因为在父子组件通信的过程中                     。父组件是处于高位是拥有控制权,而子组件在多数情况下应该为纯视图组件                     ,只负责视图的展示和自身视图的逻辑操作                     。对外交互的权利应该由父组件来控制。所以应当由父组件传递视图数据给子组件                     ,子组件负责展示              。而子组件的对外交互通过$emit触发父组件中相应的方法,再由父组件处理相应逻辑                     。

<!-- 父组件 --> <template> <div> <my-child ref="child"></my-child> </div> </template> <script> import MyChild from @components/common/MyChild export default { components: { MyChild }, mounted() { console.log(this.$refs[child].getData()); } } </script> <!-- 子组件 --> <script> export default { methods: { getData() { // do something... } } } </script>

组件样式修改 样式穿透 

sass中语法 有些像sass之类的预处理器无法正确解析 >>>       。这种情况下你可以使用 /deep/操作符取而代之——这是一个>>>的别名              ,同样可以正常工作

<style scoped> .a /deep/ .b { /* ... */ } </style>

插件使用:slot

一个通用组件                     ,往往不能够适应所有应用场景       ,所以在封装组件的时候只需要完成组件 80% 的功能              ,剩下的 20% 让父组件通过 solt 解决              。solt 起到一个占位的作用                     ,给按钮的设置提前预留一个位置       ,然后在父组件中写入按钮即可                     。

在开发通用组件的时候       ,只要不是独立性很强的组件最好是都加一个slot       。并且                     ,开发过程中              ,常常需要在子组件内添加新的内容       ,这时候可以在子组件内部留一个或者多个插口                     ,然后在调用这个子组件的时候加入内容              ,添加的内容就会分发到对应的 slot 中:

父组件 <head-component> <h2>不具名插槽</h2> <h2 slot="s1">这里对应的是s1插口</h2> <h2 slot="s2">这里对应的是s2插口</h2> </head-component> 子组件 <template> <div class="headComponent"> <h3>这是一个头部组件</h3> <slot></slot> <slot name="s1"></slot> <slot name="s2"></slot> </div> </template>

slot 中还可以作为一个作用域,在子组件中定义变量                     ,然后在父组件中自定义渲染的方式:(项目中使用的比较多                     ,vue+elementUI中ajax获取数据显示在表格中,很多时候每一条数据不是直接显示的              ,需要做一些额外的处理)

子组件 <template> <div class="headComponent"> <h3>这是一个头部组件</h3> <slot name="head" v-for="head in heads" :text="head.text"></slot> </div> </template> 父组件 <head-component> <template slot="head" scope="props"> <li> {{ props.text }} </li> </template> </head-component>

参考链接:vue组件化开发_star@星空的博客-CSDN博客

Vue公共组件的封装_Milly_Liu的博客-CSDN博客_vue公共组件的封装

vue组件化开发_star@星空的博客-CSDN博客

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
vue路由beforeeach(【vue+router】解决路由重复警告:[vue-router] Duplicate named routes definition) 企业网站优化(让你的网站在搜索引擎上获得更多曝光率)