Note source: Hook Education – big front end employment Training camp
Content: Notes, thoughts and experiences in the process of learning
Tip: project actual combat article resources can not be uploaded, only for reference
uni-app
Based on Vue+ wechat applet language system, cross-terminal development can be realized
Uni – app introduction
Uni-app is a framework that uses Vue to develop all front-end applications. Developers write a set of code, which can be published to IOS, Android, H5 and various small programs (wechat, Alipay, Baidu, Toutiao, Dingding) and other platforms, making it easy for developers to deliver quickly without changing their development thinking and habits
Why uniapp?
- Developers, numerous cases
- Platform capacity is not limited, through conditional compilation + platform specific API, does not affect other platforms
- Excellent performance experience
- Rich surrounding ecology
- Low learning cost
Uni-app can call various SDKS and apis for its own use, thus generating multi-terminal code
Development environment Setup – HBuilderX
HBuilderX is a generic front-end development tool, but has been specially enhanced for UNI-App
It is recommended that you install the app development version out of the box, otherwise you will be prompted to install the plug-in when running and publishing
- Download HBuilderX – Install
- Create a new project, select UNI-app, enter the project name and create the project
- Select run to run the program in multiple terminals, multiple terminals can run simultaneously
Initialize related configurations
Project directory structure
Note: Files in the static resource directory are not packed by Webpack, so files that need to be packed by Webpack cannot be placed here
-
Apply manifest.json configuration
- File is the configuration file of the application, can be displayed in a visual way, used to specify the name of the application, icon, permissions, etc., we can also set the cross-domain interception handler for Vue for H5 in this
- Here we need to fill in the little program appId
-
Compile configuration – vue.config.js
- Not available in initialization state, an optional configuration file for configuring WebPack compilation options, official documentation
-
Global configuration – page.json -The official documentation
-
Global configuration of Uni-app, determining page file path, window style, native navigation bar, bottom native tabbar, etc., similar to app.json of applets
-
attribute type mandatory describe globalStyle Object no Sets the window appearance of the default page pages Object Array is Set the page path and window presentation easycom Object no Components automatically import rules tabBar Object no Sets the performance of the bottom TAB condition Object no Boot Mode Configuration subPackages Object Array no Subcontract loading configuration preloadRule Object no Subcontract pre-download rules
-
-
Global style – uni.scSS -The official documentation
- Easy to control the overall application style, such as button color, border style, and a set of PRESET CSS variables
- Is a special file that can be used in SCSS code without the need to import this file
-
Main component – app.vue
- Note that it is not a page and cannot write teamplte syntax
- The purpose of this file is to call application lifecycle functions, configure global styles, and configure global storage globalData
- The application lifecycle can only be listened on app.vue, not on the page.
-
Entry file -main.js -The official documentation
- Similar to vue, both are entry files for programs
Uni-app development specification and resource path
Development specification conventions
- Page but file and VUE use the same, from top to bottom HTML, JS, CSS
- Component tags are close to the applet specification and instead of using tags such as P and div, they use applet tags such as View and text
- Interconnection capability (JS API) is close to wechat applets specification, but it needs to replace WX with UNI. See UNI-APP interface specification for details
- Data binding and event handling are the same as the vue.js specification and complement the App and page life cycles
- It is recommended that you develop with a Flex layout for multiterminal compatibility
Resource Path Description
Note: When writing uni-app code, it is recommended to use absolute paths (@/) instead of relative paths, but not out of bounds
-
To date static resources such as image, video, etc. SRC attributes within template, you can use relative or absolute paths as follows:
-
<! -- absolute path, /static: static directory in root directory, in cli project /static: static directory in SRC directory --> <image class="logo" src="/static/logo.png"></image> <image class="logo" src="@/static/logo.png"></image> <! -- Relative path --> <image class="logo" src=".. /.. /static/logo.png"></image> Copy the code
-
The @ initial absolute and relative paths are verified by base64 conversion rules
-
Static resources for appointments are not converted to Base64 on non-H5 platforms
-
H5 platform, resources less than 4KB will be converted to Base64, the rest will not be transferred
-
-
Js file or script tag, you can use relative path and absolute path, the form is as follows:
-
// Absolute path, @ points to the project root directory, in cli projects @ points to the SRC directory import add from '@/common/add.js' // Relative path import add from '.. /.. /common/add.js' Copy the code
-
-
The path of the image referenced in the CSS file or the style tag can be relative or absolute. The format is as follows:
-
/* Absolute path */ background-image: url(/static/logo.png); background-image: url(@/static/logo.png); /* Relative path */ background-image: url(. /.. /static/logo.png); Copy the code
-
The life cycle
Uni-app supports full Vue lifecycle hooks, as well as new application and page lifecyls
Application lifecycle: For the entire project, in app.vue
The function name | instructions |
---|---|
onLaunch | Triggered when uni-app initialization is complete (globally only triggered once) |
onShow | When uni-app is started, or from the background into the foreground display |
onHide | When UNI-app goes from the foreground to the background |
onError | Triggered when uni-app reports an error |
onUniNViewMessage | For details about how to listen data sent from nvUE to VUE, see NvUE Communication to VUE |
onUnhandledRejection | Reject an unprocessed Promise event listener function (2.8.1+) |
OnPageNotFound (common) | There are no listener functions on the page |
onThemeChange | Listen for system topic changes |
Page life cycle: For pages
The function name | instructions |
---|---|
onLoad | Listen to the page load. The parameter is the data passed on the previous page and the parameter type is Object (used for page parameter transfer) |
onShow | Listen to the page display. Triggered each time a page appears on the screen, the package returns from a sub-page point to reveal the current page |
onReady | The listener page is rendered for the first time. Note that if the rendering is fast, it will trigger before the page is animated |
onHide | Listening page hiding |
onUnload | Listening page uninstallation |
onResize | Listen for window size changes |
onPullDownRefresh | Listen for user pull-down actions, usually used for pull-down refresh, and need to be allowed in pages. Json |
onReachBottom | An event to scroll to the bottom of a page (not to the bottom of a scroll view), usually used to pull down data from the next page. See notes below for details |
onTabItemTap | When TAB is clicked, the parameter is Object. For details, see notes below |
onShareAppMessage | Users click on the upper right to share |
onPageScroll | Listen for page scrolling with Object |
onNavigationBarButtonTap | Listen for the native title bar button click event with the Object parameter |
onBackPress | Listening page return |
onNavigationBarSearchInputChanged | Listen for changes in the native title bar search input box |
onNavigationBarSearchInputConfirmed | Listen for the native title bar search input box search event, triggered when the user clicks the “search” button on the soft keyboard. |
onNavigationBarSearchInputClicked | Listen for native title bar search input box click events |
onShareTimeline | Listen to the user click on the upper right corner to forward to moments |
onAddToFavorites | Listen to the user click favorites in the upper right corner |
Route configuration and page redirection
The routing configuration
Uni-app page routing is all managed by the framework. Developers need to configure the path and page style of each routing page in pages. Json (similar to the configuration of page routing in app.json by applet).
"pages": [{"path": "pages/index/index"."style": {
"navigationBarTitleText": "uni-app"
}
},{
"path": "pages/new/new"."style": {
"navigationBarTitleText": "new"}},]Copy the code
Routing hop
There are two ways to redirect a page:
- Use the Navigator component to jump (tabbed navigation)
- Call API jump (programmatic navigation)
Uni-app framework manages all current pages in the form of a stack. When route switching occurs, the page stack behaves as follows:
routing | Page stack representation | trigger |
---|---|---|
Initialize the | New page is pushed | The first page uni-app opens |
Open a new page | New page is pushed | Call api-uni. navigateTo, use component |
Page redirection | The current page is out of the stack, and the new page is in the stack | Call APluni.redirectToUsing components |
The page returns | The page goes off the stack until the target returns to the page | Call APluninavigateBack, use components, users press the back button in the upper left corner, Android users click the physical Back button |
The Tab to switch | All pages are off the stack, leaving only new Tab pages | Call APluni.switchTab, use component, user switch Tab |
Heavy load | All pages are off the stack, leaving only new pages | 0 call APluni.reLaunchUsing components |
NavigateTo: uni. NavigateTo: uni. SwitchTab: uni
Gets the current page stack
The getCurrentPages() function is used to get an instance of the current page stack, as an array in stack order, with the first element being the home page and the last element being the current page.
Note: getCurrentPages() is only used to display the page stack. Do not modify the page stack to avoid page status errors.
Routing and acceptance
Page pass parameters: used directly after jump routes? Parameter name = Parameter value & Parameter name = parameter value
To pass
// Page jumps and passes parameters
uni.navigateTo({
url: 'page2? name=liy&message=Hello'
});
Copy the code
Page accepts parameters: The option parameter in the onLoad function that jumps to the target page retrieves the parameters passed in
// Page 2 receives parameters
// Option is of type object, which serializes the arguments passed on the previous page
onLoad: function (option) {
console.log(option.name); // Prints out the arguments passed from the previous page.
console.log(option.message); // Prints out the arguments passed from the previous page.
}
Copy the code
Note: URL has length limit, too long string will fail to transfer, and non-standard character format may also lead to failure to transfer, so it is recommended to use encodeURI, decodeURI for complex parameters after processing transfer
Applets routing and subcontracting configuration
Due to the limitation of size and resource loading of applets, various applets platforms provide subcontracting methods to optimize the download and startup speed of applets.
The main package is where the default startup page and TabBar page are placed, and the subpackages are divided according to the configuration of pages.json.
When the small program starts, the main package will be downloaded and the page in the main package will be started by default. When the user enters a page in the subpackage, the corresponding subpackage will be automatically downloaded and displayed after downloading. At this time, there will be a waiting prompt in the terminal interface.
// The subcontract directory only needs to be manually written when it is created for the first time. Later, creating pages directly under the directory without manual writing will automatically be added to the subcontract JSON
// Subcontract configuration
"subPackages": [{
// Subcontract catalog
"root": "subPackages".// The page under the directory is written the same as the main package
"pages": [{
"path": "chat/chat"."style": {
"navigationBarTitleText": "Talk to my soul mate."."enablePullDownRefresh": false}}}]].// Subcontract pre-download
"preloadRule": {
// Page path
"subPackages/chat/chat": {
// Download conditions: all - under any network
"network": "all"."packages": ["__APP__"]}},Copy the code
Common Components
Uni-app gives us a set of tag elements that are similar to HTML, but different from HTML, similar to applets, and more suitable for mobile use
While HTML tags are not recommended, they can be used and will automatically be converted when mutating to non-H5 platforms, but they are still not recommended
Commonly used API
H5 runs in the browser, non-H5 Android runs in the V8 engine, and iOS runs in the JScore engine of iOS. So the jsAPI of UNI-App consists of the STANDARD ECMAScript JS API and the UNI extension API.
ECMAScript is managed by Ecma International and is the basic JS syntax. Browser based on the standard JS extension window, Document AND other JS API; Node.js expands fs modules based on standard JS; Applets also extend various Wx.xx, my.xx, swan.xx apis based on standard JS.
There are many standard ECMAScript apis, such as console, setTimeout and so on.
Non-h5, although it does not support the JS API of window, Document, Navigator and other browsers, it does support standard ECMAScript.
Developers should not equate browser JS to standard JS.
So the non-H5 side of UNI-App also supports standard JS, if and for syntax, strings, arrays, time and other variables and various processing methods, but does not support browser-specific objects
Custom Components
Custom Components
Like Vue, which stores components in the component directory of the project, Uni-App only supports Vue single-file components (.vue components).
Components can be used using global registration and page import in three steps:
-
Import: import XXX from ‘XXX’
-
Use (‘xx’,xx) – global, Components :{XXX} – components
-
Use:
Intercomponent communication
Parent-child component communication
-
The parent component passes data to the child component through custom properties
-
The child component receives data passed by the parent component through props
-
The parent component passes events to child components through custom event tags
-
The child modifies the parent component data by triggering the parent component definition event
Slot Slot for data distribution and scope
-
The parent component distributes slot to the child component by calling the nested HTML content inside the child component
-
The child component communicates data to the parent component by adding properties to the slot tag, scoping the slot
Global event definition and communication
-
Uni.$ON (event name, callback function (parameter)) can be used anywhere throughout the application to create a global event
-
Uni. $emit (event name, parameter) can also be used anywhere in the entire application to trigger global events for multi-component data communication
Status management – vueX
- concept
Vuex is a state management mode developed specifically for vue.js applications. It uses centralized storage to manage the state of all components of an application and rules to ensure that the state changes in a predictable way.
- Application scenarios
Data or state needs to be shared between Vue components.
- The key rules
- State: Stores status data
- Getter: Derived data from State data, equivalent to the computed property of State
- Mutation: Stores the method used to synchronize changed state data. The default parameter passed in is state
- Action: Stores state data for asynchronous changes, not directly, but by triggering the Mutation method. The default parameter is context
- Module: Vuex modularity
/ / create vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {userName: uni.getStorageSync('userName')? uni.getStorageSync('userName') : 'Not logged in user'
},
mutations: {MLOGIN(state, userName){
uni.setStorageSync('userName', userName)
state.userName = userName
},
MLOGOUT(state){
uni.clearStorageSync()
state.userName = 'Exit status user'}},actions: {login(context, userName){
context.commit('MLOGIN', userName)
},
logout(context){
context.commit('MLOGOUT')}}})export default store
Copy the code
/ / use vuex
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
App.mpType = 'app'
// Call Store vuex state management
import store from '@/store/index.js'
if (process.env.NODE_ENV === 'development') {
console.log('Development Environment')}else {
console.log('Production environment')}const app = newVue({ ... App, store }) app.$mount()Copy the code
- use
// mapState - get all states, mapActions - get all Actions
import { mapState, mapActions } from 'vuex'
export default {
// Calculate attributes: direct destruct
computed: { ...mapState(['loginState'.'userInfo'])},// Method - direct deconstruction
methods: { ...mapActions(['userLoginAction'.'userLogoutAction'])}}Copy the code
The operating environment is cross-compatible
Development environment and production environment
Uni-app uses process.env.node_env to determine whether the current environment is a development environment or a production environment. It is generally used to connect to test servers or production servers for dynamic switching.
In HBuilderX, clicking “run” to compile code is the development environment, and clicking “publish” to compile code is the production environment
if(process.env.NODE_ENV === 'development') {console.log('Development Environment')}else{
console.log('Production environment'),}Copy the code
Judge platform
Platform judgment has two scenarios, one is at compile time and the other is at run time.
(Recommended) Compile-time check Compile-time check, that is, conditional compilation. Different platforms have different code after the package is compiled
// #ifdef H5
alert("Only H5 platform has alert method")
// #endif
// The above code will only be compiled into the H5 distribution, other packages will not include the above code.
Copy the code
Run-time check Run-time check indicates that you still need to check the platform during runtime after the code has been sent to the package. In this case, use uni.getSystemInfosync (). Platform to check whether the client environment is Android, iOS or a small program development tool
switch(uni.getSystemInfoSync().platform){
case 'android':
console.log('Running on Android')
break;
case 'ios':
console.log('Running on iOS')
break;
default:
console.log('Running on developer tools')
break;
}
Copy the code
Across the compatible
Uni-app has encapsulated common components and JS apis into the framework. Developers can develop according to uni-App specifications to ensure the compatibility of multiple platforms, and most services can be directly satisfied. However, each platform has its own characteristics, so some platforms cannot be cross-platform.
- Writing a lot of if-else can lead to poor code performance and confusing management.
- Compiling to a different project and then modifying it twice can make subsequent upgrades very troublesome.
C uses #ifdef, #ifndef to compile different code for Windows, MAC, and other oss. Uni-app takes this idea into consideration and provides uni-App with a conditional compilation method, which gracefully implements platform personalization in a single project.
Conditional compilation is marked with special comments that are used to compile code for different platforms at compile time.
Writing: Start with #ifdef or #ifndef plus %PLATFORM% and end with #endif.
\#ifdef
: if defined exists only on a platform\#ifndef
: if not defined Exists except for a platform%PLATFORM%
: Platform name
%PLATFORM% can be:
value | platform |
---|---|
APP-PLUS | App |
APP-PLUS-NVUE | App nvue |
H5 | H5 |
MP-WEIXIN | Wechat applets |
MP-ALIPAY | Alipay small program |
MP-BAIDU | Baidu applet |
MP-TOUTIAO | Bytedance applet |
MP-QQ | QQ small programs |
MP-360 | 360 small programs |
MP | Wechat small program/Alipay small program/Baidu small program/bytedance small program /QQ small program /360 small program |
QUICKAPP-WEBVIEW | Quick Application General (including Alliance and Huawei) |
QUICKAPP-WEBVIEW- UNION | Fast Application Alliance |
QUICKAPP-WEBVIEW- HUAWEI | Quick Application Huawei |
Bosom Brother project practice
- Vuex data can be changed on the home page
- Bosom brother page can realize dialogue function
{
"pages": [{"path": "pages/index/index"."style": {
"navigationBarTitleText": "uni-app"}}, {"path": "pages/me/me"."style": {
"navigationBarTitleText": ""."enablePullDownRefresh": false}}, {"path": "pages/404/404"."style": {
"navigationBarTitleText": ""."enablePullDownRefresh": false}}, {"path": "pages/list/list"."style": {
"navigationBarTitleText": ""."enablePullDownRefresh": false}}, {"path": "pages/find/find"."style": {
"navigationBarTitleText": ""."enablePullDownRefresh": false}}, {"path": "subpages/chat/chat"."style": {
"navigationBarTitleText": ""."enablePullDownRefresh": false}}].// Subcontract page
"subPackages": [{
"root": "subPackages"."pages": [{
// Open the page
"path": "chat/chat"."style": {
"navigationBarTitleText": "Talk to my soul mate."."enablePullDownRefresh": false}}, {"path": "new/new"."style": {
"navigationBarTitleText": ""."enablePullDownRefresh": false}}}]]./ / preload
"preloadRule": {
"subPackages/chat/chat": {
"network": "all"."packages": ["__APP__"]}},"globalStyle": {
"navigationBarTextStyle": "black"."navigationBarTitleText": "uni-app"."navigationBarBackgroundColor": "#F8F8F8"."backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#7A7E83"."selectedColor": "#3cc51f"."borderStyle": "black"."backgroundColor": "#ffffff"."list": [{
"pagePath": "pages/index/index"."iconPath": "static/tabbar-icons/wx.png"."selectedIconPath": "static/tabbar-icons/wx_s.png"."text": "WeChat"
}, {
"pagePath": "pages/list/list"."iconPath": "static/tabbar-icons/list.png"."selectedIconPath": "static/tabbar-icons/list_s.png"."text": "A list"
}, {
"pagePath": "pages/find/find"."iconPath": "static/tabbar-icons/find.png"."selectedIconPath": "static/tabbar-icons/find_s.png"."text": "Discovered"
}, {
"pagePath": "pages/me/me"."iconPath": "static/tabbar-icons/me.png"."selectedIconPath": "static/tabbar-icons/me_s.png"."text": "我"}}}]Copy the code
<template> <view class="content"> <! <navigator URL ="/subPackages/chat/chat" </navigator> <! Vuex --> <text> {{userName}}</text> <! -- Button to log in and log out, @click="login(' CWN ')"> </button> <button type="default" </button> </view> </template> <script> vuex import {mapState, MapActions} from 'vuex' export default {data() {return {}}, // MapActions (['login','logout'])}, // Calculates attributes to deconstruct data computed: {... mapState(['userName']) } } </script> <style> .content { display: flex; flex-direction: column; align-items: center; justify-content: center; } .logo { height: 200rpx; width: 200rpx; margin-top: 200rpx; margin-left: auto; margin-right: auto; margin-bottom: 50rpx; } .text-area { display: flex; justify-content: center; } .title { font-size: 36rpx; color: #8f8f94; } </style>Copy the code
/ / use vuex
import App from './App'
// Import the created vuex instance
import store from '@/store/index.js'
// #ifndef VUE3
import Vue from 'vue'
Vue.config.productionTip = false
App.mpType = 'app'
const app = newVue({ ... App,/ / use vuex
store
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif
Copy the code
// Introduce vue and vuex
import Vue from 'vue'
import Vuex from 'vuex'
// Globally register vuex
Vue.use(Vuex)
// Create an instance
const store = new Vuex.Store({
/ / data
state: {
// Obtain from local data
userName: uni.getStorageSync('userName')? uni.getStorageSync('userName') : 'Not logged in user'
},
// Change the method
mutations: {
/ / login
TOIN(state, userName) {
state.userName = userName
uni.setStorageSync('userName', userName)
},
/ / exit
TOOUT(state) {
state.userName = 'Not logged in'
uni.setStorageSync('userName')}},// Asynchronous method
actions: {
/ / login
login(context, userName) {
context.commit('TOIN',userName)
},
/ / exit
logout(context) {
context.commit('TOOUT')}}})export default store
Copy the code
<template> <view class="container"> <! <view class="chat-body"> <! <block v-for="(item,index) in chatList" :key='index'> <! <view class="chat-one" v-if="! item.isme"> <image class="chat-face" src="@/static/faces/1-thump.jpg" /> <view class="chat-box"> <view Class ="chat-sender"> <view > <view class="chat-content" V-if ="item.type === 'TXT '">{{item.content}}</view> <image class="chat-img" :src="item.content" mode="widthFix" v-else></image> </view> </view> <! -- My structure, <view class="chat-one chat-one-mine" V-else > <view class="chat-box"> <view class="chat-content" v-if="item.type === 'txt'">{{item.content}}</view> <image class="chat-img" :src="item.content" mode="widthFix" v-else></image> </view> <image class="chat-face" src="@/static/faces/6-thump.jpg" /> </view> </block> </view> <! <view class="chat-footer"> <! <input class=" msG-input "type="text" cursor-spacing="16" V-model ="myInput"/> <! <image class="img-chose" SRC ="@/static/img. PNG "@click="choseImgAndSend" /> <! <view class="send-btn" @click="sendMsg"> send </view> </view> </template> <script> export default { Data () {return {myInput: ", // chatList: [{isme: false, type: 'TXT ', content: }, {isme: false, type: 'img', content: '/static/faces/6-thump.jpg'}, {isme: true, type: 'TXT ', content:' wow, you are beautiful !!!!'}, {isme: true, type: 'img', content: '/static/faces/6-thump.jpg' }, ] } }, If (uni.getStoragesync ('chatList')) {// Replace data this.chatList = Parse (uni.getStoragesync ('chatList')) // Slide to the bottom setTimeout(() => {uni.pagesCrollto ({scrollTop: 9999999, duration: Select uni. ChooseImage ({// only 1 count: SourceType: ['album', 'camera'], // success: This.chatlist.push ({isme: true, type: 'img', content: This.chatlist. Push ({isme: false, type: 'img', content: Res.tempfilepaths [0]}) // Turn bottom setTimeout(() => {uni.pagesCrollto ({scrollTop: 9999999, duration: SetStorageSync ('chatList', json.stringify (this.chatList)); }})}, // send text event function sendMsg() {// determine whether to enter if(this.myinput! This.chatlist.push ({isme: true, type: 'TXT ', content: this.myInput}) this.chatList.push({isme: true, type:' TXT ', content: this.myInput}) this.chatList.push({isme: False, type: 'TXT ', content: this.myInput}) setTimeout(() => {uni.pagescrollto ({scrollTop: 9999999, duration: 100})}, 5) // Save data uni.setStoragesync ('chatList', JSON.stringify(this.chatlist)); // reset input this.myInput ="}}}} </script> <style lang=" SCSS "scoped>. Container {background-color: #f1f1f1; min-height: 100vh; } .chat-body { padding-bottom: 178upx; .chat-time { text-align: center; color: #888; padding: 40upx 0 0; } .chat-one { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: flex-start; align-items: flex-start; padding: 20upx 0; } .chat-one-begin { padding: 40upx 0 0; } .chat-one-mine { justify-content: flex-end; } .chat-face { width: 84upx; height: 84upx; border-radius: 10upx; margin-left: 40upx; } .chat-one-mine .chat-face { margin-left: 0; margin-right: 40upx; } .chat-box { max-width: calc(100% - 290upx); margin-left: 20upx; font-size: 30upx; } .chat-one-mine .chat-box { margin-right: 20upx; } .chat-sender { color: #888; font-size: 28upx; margin-top: -8upx; margin-bottom: 10upx; } .chat-content { background-color: #fff; border-radius: 5px; padding: 10px; .micon { margin-right: 20upx; color: #666; } } .chat-img { float: left; max-width: 60%; border-radius: 5px; } .chat-one-mine .chat-img { float: right; } } .chat-footer { width: 670upx; padding: 0 40upx; height: 120upx; position: fixed; bottom: 0; left: 0; background-color: #f1f1f1; display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-between; align-items: center; align-content: center; border-top: 1upx solid #ddd; .msg-input { background-color: #fff; width: calc(100% - 300upx); height: 70upx; line-height: 70upx; font-size: 30upx; border-radius: 10upx; padding: 0 20upx; } .img-chose { height: 70upx; width: 70upx; } .send-btn { height: 60upx; line-height: 60upx; width: 120upx; text-align: center; background-color: green; color: #FFFFFF; border-radius: 12upx; } } </style>Copy the code