封装
封装框架组件
方法一(自己写框架时可以这么干):
假设我们自己封装了一个 组件
my-demo
,并且在 组件A
中调用了组件my-demo
。
组件 my-demo
中:
- HTML代码该怎么写还怎么写
- CSS 代码该怎么写还怎么写
- JS 代码:
- 原来写在
data
中的变量,现在要写到prop
中 - 原来写在
methods
中的方法,现在要把事件发送给父组件
- 原来写在
组件A
中:
- import 导入封装的组件
- components 中注册封装的组件
- 在 HTML 中使用封装的组件
DEMO:
开发框架(库)以及IDE:
IDE:HBuilder X (3.1.13.20210514 版本)
框架:vue(2.0 版本)、uniapp、uView (1.8.4 版本)、ColorUi(2.1.6 版本)
封装的组件 components/my-demo/my-demo.vue
:
<template>
<view>
<view v-for="(item, index) in listSon" :key="index" @click="doClose(index, 'HelloWorld')">
<view v-if="show">
<view>小组号:{{ num }}</view>
<view>姓名:{{ item.name }}</view>
<view>年龄:{{ item.age}}</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "my-demo",
props: {
list: {
// 数组,默认为空
type: Array,
default: [],
},
show: {
// 是否显示,默认显示
type: [Boolean, String],
default: true,
},
num: {
// 数字,默认0
type: [Number, String],
default: 0,
}
},
data() {
return {
listSon: this.list,
};
},
watch: {
list(val) {
this.listSon= val;
},
},
methods: {
doClose(index, msg) {
// 发送事件给父组件
// 父组件通过 @clickThis 触发,且可以获得两个参数
this.$emit("clickThis", index, msg);
}
}
}
</script>
<style>
// 略
</style>
在组件A中,调用封装的组件:
<template>
<view>
<my-demo
:list="theList"
:show="theShow"
:num="theNum"
@clickThis="doThis"
></my-demo>
</view>
</template>
<script>
import myDemo from "@/components/my-demo/my-demo.vue";
export default {
components: { myDemo },
data: {
return {
theList: [1,3,5,7,9],
theShow: false,
theNum: 520
}
},
methods: {
doThis(index, msg) {
this.theNum = index;
this.theList.push(8);
this.theShow = !this.theShow;
}
}
}
</script>
<style>
// 略
</style>
番外:
自己写是很容易会出现此 BUG:
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value.
如图:
原因大多是:在子组件中改动了 props 中的值。
解决办法是:在子组件的data
中声明变量,将props
的值赋给此变量,通过watch
监听改变变量。这样避免了直接更改 props 中的值,就不会报错。
方法二:
以封装
ElementUI
的Message 消息提示
为例
- 官方提供的使用教程:
<template>
<el-button :plain="true" @click="open2">成功</el-button>
</template>
<script>
export default {
methods: {
open2() {
this.$message({
message: '恭喜你,这是一条成功消息',
type: 'success'
});
},
}
}
</script>
- 自定义框架的
$message
方法为$baseMessage
,并使$baseMessage
可以全局使用:
1、在 vue 原型上定义 $baseMessage
:
src/utils/prototype.js
:
import { Message } from 'element-ui'
const install = (Vue) => {
/* 全局Message */
Vue.prototype.$baseMessage = (message, type) => {
Message({
offset: 60,
showClose: true,
message: message,
type: type,
dangerouslyUseHTMLString: true,
duration: 3000,
})
}
}
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
export default install
2、引入自己定义的(亦可在main.js
中直接引入):
src/plugins/index.js
:
/**
* @author mygoes mygoes@sohu.com
* @description 插件的公共引入
*/
import Vue from 'vue'
import MyGoes from '@/utils/prototype'
Vue.use(MyGoes)
3、在main.js
中引入:
main.js
:
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import './plugins'
Vue.use(ElementUI);
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
4、在页面中使用:
可以用
this.
直接使用$baseMessage
;
也可以用Vue.prototype.
使用$baseMessage
,但记得import
引入一下Vue
。
<template>
<div>
<el-button @click="btn">点击测试1</el-button>
<el-button @click="btn2">点击测试2</el-button>
</div>
</template>
<script>
import Vue from "vue";
export default {
methods: {
btn() {
Vue.prototype.$baseMessage("测试1成功", "success");
},
btn2() {
this.$baseMessage("测试2成功", "success");
},
},
};
</script>
项目源码
模块封装
在模块中对外输出变量:
// hello.js
'use strict';
var s = 'Hello';
function greet(name) {
console.log(s + ', ' + name + '!');
}
module.exports = greet;
引入其他模块输出的对象:
// world.js
'use strict';
// 引入hello模块:
var greet = require('./hello');
var s = 'Michael';
greet(s); // Hello, Michael!
一些常用 js 的封装:
时间倒计时(现在 到 目标时间)
/**
* @description:时间倒计时(现在 到 目标时间)
* @param {date} 目标时间: '2020.11.17 17:54:00'
* @return: 剩余时间
*/
Countdown = (date) => {
date = date.replace(/\./g, '/');
let timestamp = (new Date(date)).valueOf();
let nowStr = (new Date()).valueOf();
let remain = (timestamp - nowStr) / 1000;
if (remain < 0) {
remain = 0;
}
let days = Math.floor(remain / 3600 / 24),
hours = Math.floor((remain / 3600) % 24),
minutes = Math.floor((remain % 3600) / 60),
seconds = Math.floor((remain % 3600) % 60);
if (hours < 10) hours = "0" + hours;
if (minutes < 10) minutes = "0" + minutes;
if (seconds < 10) seconds = "0" + seconds;
return {
days: days,
hours: hours,
minutes: minutes,
seconds: seconds,
}
};
// 尝试使用:
console.log(Countdown('2080.11.17 00:00:00'));
时间转换(2022-11-18T08:47:14.502Z 到 2022/11/18 08:47:14)
renderTime = (date) => {
let dateee = new Date(date).toJSON();
return new Date(dateee).toISOString().replace(/T/g, ' ').replace(/-/g, '/').replace(/\.[\d]{3}Z/, '')
}
// 尝试使用:
console.log('时间转换', renderTime('2020-11-18T08:47:14.502Z'));
时间
2020-11-18T08:47:14.502Z
已转换为2020/11/18 08:47:14
。
可对replace
进行修改实现自定义的时间输出格式。
浮点数转换为金钱大写
/**
* @description:将浮点数转换为金钱大写
* @method cnMoneyFormat
* @param {Number} money 浮点数
*/
export function changeMoneyFormat(money) {
var cnMoney = '零元整'
var strOutput = ''
var strUnit = '仟佰拾亿仟佰拾万仟佰拾元角分'
money += '00'
var intPos = money.indexOf('.')
if (intPos >= 0) {
money = money.substring(0, intPos) + money.substr(intPos + 1, 2)
}
strUnit = strUnit.substr(strUnit.length - money.length)
for (var i = 0; i < money.length; i++) {
strOutput +=
'零壹贰叁肆伍陆柒捌玖'.substr(money.substr(i, 1), 1) +
strUnit.substr(i, 1)
}
cnMoney = strOutput
.replace(/零角零分$/, '整')
.replace(/零[仟佰拾]/g, '零')
.replace(/零{2,}/g, '零')
.replace(/零([亿|万])/g, '$1')
.replace(/零+元/, '元')
.replace(/亿零{0,3}万/, '亿')
.replace(/^元/, '零元')
return cnMoney
}