├── README.md
├── customeSessionWidget.js
├── customeSessionWidget.json
├── customeSessionWidget.wxml
├── customeSessionWidget.wxss
└── picture
├── 1.png
├── 2.png
├── 3.png
├── 4.png
└── GIF.gif
/README.md:
--------------------------------------------------------------------------------
1 | # InputWidget
2 | 一个适用于微信小程序的输入组件, 可以发送文字,语音, 图片
3 |
4 | # 效果
5 |
6 |
7 | ### 切换到文字
8 |
9 |
10 | ### 切换到语音
11 |
12 |
13 | ### 录音
14 |
15 |
16 | ### 取消录音
17 |
18 |
19 |
20 |
21 |
22 | # 使用
23 | 文件置于components/customeSessionWidget文件夹下面
24 | 在所需要页面json文件引用改自定义组件, 路径根据具体文件结构决定
25 | ```
26 | "usingComponents": {
27 | "customeSessionWidget": "../../components/customeSessionWidget/customeSessionWidget",
28 | }
29 | ```
30 |
31 | 在页面的wxml中使用该自定义组件
32 | ```
33 |
34 | ```
35 |
36 | 需要绑定send事件, 该事件会在确认发送文字,确认发送图片, 以及确认发送语音时触发
37 |
38 | 根据发送的不同内容, 事件对象分别如下:(通过e.detail获取)
39 | ```
40 | {
41 | content: 'xxxxx',
42 | type: 'text'
43 | }
44 | {
45 | tempFilePaths: [path1, path2],
46 | type: 'picture'
47 | }
48 | {
49 | tempFilePath: path,
50 | type: 'voice'
51 | }
52 | ```
53 |
--------------------------------------------------------------------------------
/customeSessionWidget.js:
--------------------------------------------------------------------------------
1 | // component/customeSessionWidget.js
2 | Component({
3 | /**
4 | * 组件的属性列表
5 | */
6 | properties: {
7 |
8 | },
9 |
10 | /**
11 | * 组件的初始数据
12 | */
13 | data: {
14 | // 输入组件的图标
15 | voiceIcon: "http://120.78.124.36/wxxcx/C_PLP/shengyin.png",
16 | keyboardIcon: "http://120.78.124.36/wxxcx/C_PLP/keyboard_icon.png",
17 | pictureIcon: "http://120.78.124.36/wxxcx/C_PLP/tupian.png",
18 |
19 | //录音中 取消发送的图标
20 | statusIcon: "",
21 | voicingIcon: "http://120.78.124.36/wxxcx/C_PLP/luyinzhong.png",
22 | cancelSendIcon: "http://120.78.124.36/wxxcx/C_PLP/quxiaofasong.png",
23 |
24 | tip: "",
25 | tip1: "手指上滑,取消发送",
26 | tip2: "松开手指, 取消发送",
27 |
28 | keyboardTip: "",
29 | keyboardTip1: "按住 说话",
30 | keyboardTip2: "松开 结束",
31 |
32 | selectedInputWay: 0, //选择的输入方式 只能是0和1 0:键盘 1:语音
33 | startY: 0, //按住说话 初始触摸位置
34 | spaceDistance: -100, //出现 取消发送的 Y轴距离间隔
35 | showRecordStatusView: false, //显示 录音状态的 view
36 | cancelSendStatus: false, //是否为 取消发送 状态
37 |
38 | hasRecordSetting: false, //是否拥有录音权限
39 |
40 | inputContent: "", //输入框值
41 | },
42 |
43 | /**
44 | * 组件的方法列表
45 | */
46 | methods: {
47 | checkSetting: function () {
48 | //如果 当前输入方式是文字输入,点击icon时(也就是准备切换语音输入), 提前查询权限
49 | var that = this;
50 | return new Promise((resolve, reject) => {
51 | if (that.data.selectedInputWay == 0) {
52 | wx.getSetting({
53 | success(res) {
54 | if (!res.authSetting['scope.record']) {
55 | wx.authorize({
56 | scope: 'scope.record',
57 | success() {
58 | // 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问
59 | console.log("获取录音权限成功");
60 | that.data.hasRecordSetting = true;
61 | resolve();
62 | },
63 | fail: (err) => {
64 | console.log(err);
65 | reject();
66 | }
67 | })
68 | } else {
69 | that.data.hasRecordSetting = true;
70 | resolve();
71 | }
72 | },
73 | fail: (err) => {
74 | console.log(err);
75 | reject();
76 | }
77 | });
78 | }
79 | });
80 | },
81 | //输入框值改变事件
82 | changeInputContent: function (e) {
83 | this.setData({
84 | inputContent: e.detail.value
85 | });
86 | },
87 | changeInputWay: function () {
88 | var that = this;
89 | if (!this.data.hasRecordSetting) {
90 | this.checkSetting().then(() => {
91 | that.setData({
92 | selectedInputWay: this.data.selectedInputWay == 0 ? 1 : 0,
93 | keyboardTip: this.data.keyboardTip1
94 | });
95 | }).catch(() => {
96 | wx.showModal({
97 | title: '提示',
98 | content: '未授权录音功能',
99 | showCancel:false
100 | })
101 | });
102 | } else {
103 | that.setData({
104 | selectedInputWay: this.data.selectedInputWay == 0 ? 1 : 0,
105 | keyboardTip: this.data.keyboardTip1
106 | });
107 | }
108 | },
109 | touchStart: function (e) {
110 | console.log(e)
111 | var startY = e.touches[0].clientY; //初始Y坐标
112 | this.setData({
113 | showRecordStatusView: true,
114 | startY: startY,
115 | keyboardTip: this.data.keyboardTip2,
116 | tip: this.data.tip1,
117 | statusIcon: this.data.voicingIcon
118 | });
119 | this.record();
120 | },
121 | touchMove: function (e) {
122 | var moveY = e.touches[0].clientY; //移动的Y坐标
123 | if (moveY - this.data.startY <= this.data.spaceDistance) {
124 | this.setData({
125 | cancelSendStatus: true,
126 | tip: this.data.tip2, //显示提示语改变
127 | statusIcon: this.data.cancelSendIcon
128 | });
129 | } else {
130 | this.setData({
131 | cancelSendStatus: false,
132 | tip: this.data.tip1, //显示提示语改变
133 | statusIcon: this.data.voicingIcon
134 | });
135 | }
136 | },
137 | touchEnd: function (e) {
138 | wx.stopRecord();
139 | this.setData({
140 | keyboardTip: this.data.keyboardTip1,
141 | showRecordStatusView: false
142 | });
143 | if (!this.data.cancelSendStatus) {
144 |
145 | }
146 | },
147 | //录音
148 | record: function () {
149 | var that = this;
150 | wx.startRecord({
151 | success(res) {
152 | console.log(res);
153 | if (!that.data.cancelSendStatus) {
154 | that.triggerEvent('send', { tempFilePath: res.tempFilePath, type: 'voice'});
155 | }
156 | },
157 | fail: (err) =>{
158 | console.log(err);
159 | wx.showToast({
160 | title: '录音错误',
161 | duration: 500
162 | });
163 | }
164 | })
165 | },
166 | //发送文本
167 | sendText: function () {
168 | if (!this.data.inputContent) {
169 | return;
170 | }
171 | this.triggerEvent('send', { content: this.data.inputContent, type: 'text' });
172 | this.setData({
173 | inputContent: ''
174 | });
175 | },
176 | //发送图片
177 | sendMessage: function () {
178 | var that = this;
179 | wx.chooseImage({
180 | count: 9, // 默认9
181 | sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
182 | sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
183 | success: res => {
184 | // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
185 | that.triggerEvent('send', { tempFilePaths: res.tempFilePaths, type: 'picture' });
186 | },
187 | fail: (err) => {
188 | console.log(err);
189 | }
190 | });
191 | }
192 |
193 | }
194 | })
195 |
--------------------------------------------------------------------------------
/customeSessionWidget.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
--------------------------------------------------------------------------------
/customeSessionWidget.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
8 |
9 | {{keyboardTip}}
11 |
12 |
13 |
14 |
15 |
16 | {{tip}}
17 |
18 |
--------------------------------------------------------------------------------
/customeSessionWidget.wxss:
--------------------------------------------------------------------------------
1 | /* component/customeSessionWidget.wxss */
2 | .session-view {
3 | display: flex;
4 | flex-direction: rows;
5 | justify-content: flex-start;
6 | background-color: #eee;
7 | padding: 20rpx 20rpx 60rpx 20rpx;
8 | align-items: center; /*项目在行中居中对齐, 不然会出现图片和中间view对不齐情况*/
9 | position: fixed;
10 | bottom: 0;
11 | left: 0;
12 | right: 0;
13 | border-top: 1px solid rgb(158, 158, 158);
14 | }
15 |
16 | .middle-view{
17 | width: 100%;
18 | margin: 0 20rpx;
19 | border: 1px solid rgb(158, 158, 158);
20 | padding: 15rpx;
21 | border-radius: 10rpx;
22 | text-align: center;
23 | background-color: #fff;
24 | }
25 |
26 | .iconImage {
27 | width: 60rpx;
28 | height: 50rpx;
29 | }
30 |
31 | .voice-tip {
32 | position: fixed;
33 | width: 300rpx;
34 | height: 250rpx;
35 | left: 50%;
36 | margin-left: -150rpx;
37 | top: 40%;
38 | margin-top: -150rpx;
39 | background-color: #555151;
40 | color: #fff;
41 | text-align: center;
42 | padding: 20rpx;
43 | border-radius: 20rpx;
44 | font-size: 30rpx;
45 | }
46 |
47 | .voice-tip image{
48 | width: 150rpx;
49 | height: 170rpx;
50 | }
51 |
--------------------------------------------------------------------------------
/picture/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SJcz/InputWidget/dda62476203a77a04ed3cc878182334703a07bc4/picture/1.png
--------------------------------------------------------------------------------
/picture/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SJcz/InputWidget/dda62476203a77a04ed3cc878182334703a07bc4/picture/2.png
--------------------------------------------------------------------------------
/picture/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SJcz/InputWidget/dda62476203a77a04ed3cc878182334703a07bc4/picture/3.png
--------------------------------------------------------------------------------
/picture/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SJcz/InputWidget/dda62476203a77a04ed3cc878182334703a07bc4/picture/4.png
--------------------------------------------------------------------------------
/picture/GIF.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SJcz/InputWidget/dda62476203a77a04ed3cc878182334703a07bc4/picture/GIF.gif
--------------------------------------------------------------------------------