当前位置:网站首页>How to realize sliding operation component in fast application
How to realize sliding operation component in fast application
2022-07-07 08:48:00 【Huawei Developer Forum】
1. What is a sliding operation component
In the actual way of mobile application interaction , The most common is the sliding operation . Like sliding left and right to switch pages , Open your fingers to enlarge the picture , It is all done by sliding . In this paper, the sliding operation component refers to the hidden operation button through gesture sliding .
As shown in the figure below :
chart 1 QQ app | chart 2 Huawei SMS app |
The above sliding operation components have the following characteristics :
- Both left and right sliding support , Slide to exhale 、 Hide the operation button bar ;
- Operation buttons can be configured with multiple ;
- Operate the button to set the background color 、 typeface 、 Width etc. ;
- Click the operation button , You can hide the operation bar ;
- When calling out the operation bar , Interface all UI Elements move accordingly ;
2 Basic implementation
2.1 Sliding operation component design
Define components that support sliding operations swipe_item, Parent component reference , Pass action buttons when referencing 、 Operation button style . The sliding operation sub component needs to realize gesture sliding processing .
The code structure is as follows :
<import name="swipeitem" src="../Component/swipe_item.ux"></import><template><div class="container"><swipeitem right-options="{{rightBtns}}" left-options="{{leftBtns}}" @swipebtnclick="swipeItemClick"><text> There are mixed scrolls on both sides </text></swipeitem></div></template>
2.2 Child components swipe_item Attribute design
2.3 Supported properties
attribute | type | Whether the choice | The default value is | describe |
identity | Number | no | Component unique identification , When autoClose by true when , You have to set | |
disabled | Boolean | no | false | Whether sliding is prohibited |
autoClose | Boolean | yes | true | Slide to open the current component , Whether to close other components |
threshold | Number | no | 30 | Slide the default distance |
leftOptions | Array[Option] | no | The content and style of the left operation bar | |
rightOptions | Array[Option] | no | The content and style of the right operation bar |
Option The object parameters are as follows :
attribute | type | Whether the choice | describe |
txt | String | no | Button text |
style | Object | yes | Button style |
style The object parameters are as follows :
attribute | type | Whether the choice | describe |
backgroundColor | Color | no | Button background color |
txtColor | Color | no | Button color |
fontsize | Number | no | Text size |
btnwidth | Number | yes | Button width |
Supported events
Event name | Event passing parameters | describe |
swipebtnclick | {clickIndex:1, position:left|right, btnValue:btnText} | The event will be triggered when the button on the operation bar is clicked ; clickIndex: Click the button array index on the left or right operation bar ; position: The position of the operation bar clicked , The parameter values are left and right; btnValue: Click the button text ; |
centerclick | {} | An event is triggered when you click the content displayed in the middle of the screen |
swipestatechange | {isOpened:true|false} | Triggered when the action bar is opened or closed |
2.4 swipe_item Sub component layout
- Layout structure : From the left operation bar + The middle screen displays content + Horizontal composed of the right operation bar div;
- Left operation bar 、 The right operation bar is based on leftOptions、rightOptions Operation option content array , For adoption for Loop to form horizontal layout rendering ;
- The content displayed on the screen in the middle is dynamic , The content to be displayed for each product and UI Is different , So we used slot slot , By use swipe_item Component page to complete the layout of the intermediate content .
- The width of the middle layout needs to set the width of the whole screen , namely 750px;
2.5 swipe_item Child components css
- Width : Although the left and right operation bars of the sliding operation component are hidden in the initial state , But it is actually part of the whole layout , If the width of the root node cannot be calculated correctly , When it will cause sliding , There is nothing on the operation bar .
- Animation : In the initial state , The left and right operation bars need to be hidden , Only the middle content is visible . Under normal layout ( See the picture 3), The left operation bar is displayed , So we used transform Animation style , Translate the root node by the width of the left operation bar , This ensures that the operation bar is hidden in the initial state .
- Button background color 、 Text size 、 Text color : If the parent component is not set , Set the default value of the sub component , See the picture 4;
chart 3 Normal layout effect | chart 4 The default background color effect of operation bar buttons |
2.6 Gesture slide
Monitor gestures touchstart、touchmove、touchend event , Calculate the sliding pixels of fingers , At the same time call X Translation animation of axis animate Method , Realize the moving effect of components .
- touchstart: Record the starting touch point ;
- touchmove: Sliding distance ds>0 Indicates that the finger slides to the right , On the contrary, slide left , During the sliding process animate() Mobile components , Achieve the effect of opening or hiding the operation bar ; If the sliding distance is less than the threshold threshold, Do not trigger the movement effect ; If sliding is prohibited, that is disabled The value is true when , Nor can it trigger the sliding effect ;
- touchend: Triggered at the end of the slide , call animate() Control the final display position of the operation bar , Need to calculate accurately , Prevent components from moving too far or too close , thus UI The effect is abnormal .
2.8 Parent-child component communication
When you click the button on the sub component operation bar , The parent component is required to handle the business logic , adopt $emit() Send notification to parent component . Be careful , Do not deal with business logic in subcomponents , Otherwise, the code cannot be maintained .
1) Click the event notification button on the operation bar
- When a page calls a sub component , monitor swipebtnclick event ;
- Subcomponent call $emit() Send a notification to the page ;
2) Click event notification in the middle part
- When a page calls a sub component , monitor centerclick event ;
- When the operation bar is open , Click the middle part to hide the operation bar . Only when the operation bar is hidden , When clicking on the middle part , Subcomponent call $emit() Send a notification to the page , The page handles the business logic by itself , For example, open a new page .
3) The operation bar opens 、 Turn off event notification
- When a page calls a sub component , monitor swipestatechange event ;
- When the operation bar is open or closed , Subcomponent call $emit() Send a notification to the page .
The relevant code is as follows :
2.9 autoClose Realization
When sliding to open the current component , Whether to close other components , When autoClose Set to true when ,identity Property must be set , And uniquely identify the current sub component .
- When Child components 1 When the operation bar is opened , adopt $emit() Send status event to page swipestatechange;
- Parent listening swipestatechange event , adopt $broadcast() Method to send a shutdown notification event to the sub component closeSwipeItem, Inform others Child components 2,3,4 Wait to close the open operation bar ;
- Child components 1,2,3,4 Wait until the monitoring is turned off closeSwipeItem event , Handle the closing logic in the event handle , Note that the operation bar opens Child components 1 You will also receive a shutdown event , Here we need to judge identity value , Make sure that the newly opened Child components 1 There will be no phenomenon of opening and closing .
3 summary
- Learn and be familiar with the design and attribute definition of quick application sub components ;
- Learn and be familiar with fast application gesture events ;
- Learn and be familiar with fast application animation ;
- Pay attention to the sliding operation sub assembly swipe_item stay list-item China doesn't work .
4 Code appendix
Slide operation sub assembly swipe_item.ux
<template> <!-- Only one root node is allowed in template. --> <div class="container" style="{{containerStyle}}" > <div id="swipe_item" class="swipe" ontouchstart="dealTouchStart" ontouchmove="dealTouchMove" ontouchend="dealTouchEnd" > <div class="left" id="leftbtns"> <block for="(index,item) in leftOptions"> <input type="button" class="btn" style="background-color: {{calBtnBgColor(item.style.backgroundColor)}}; color:{{calBtnTxtColor(item.style.txtColor)}}; font-size:{{calBtnFontSize(item.style.fontsize)}}px;width:{{item.style.btnwidth}}px;" value="{{item.txt}}" onclick="btnsClick(index,'left',item.txt)"> </input> </block> </div> <div class="center" style="width:{{deviceLogicWidth}}px" onclick="dealClickCenter"> <slot ></slot> </div> <div class="right" id="rightbtns"> <block for="(index,item) in rightOptions"> <input type="button" class="btn" style="background-color: {{calBtnBgColor(item.style.backgroundColor)}}; color:{{calBtnTxtColor(item.style.txtColor)}}; font-size:{{calBtnFontSize(item.style.fontsize)}}px;width:{{item.style.btnwidth}}px;" value="{{item.txt}}" onclick="btnsClick(index,'right',item.txt)"> </input> </block> </div> </div> </div></template><style> .container { flex-direction: column; justify-content: center; } .swipe { flex-direction: row; align-items: center; } .txt { font-size: 40px; width: 100%; height: 100%; } .btn { height: 100%; } .left { flex-direction: row; flex-shrink: 0; height: 100%; background-color: #a9a9a9; } .center { flex-direction: row; align-items: center; padding: 16px; flex-shrink: 0; } .right { flex-direction: row; flex-shrink: 0; height: 100%; background-color: #a9a9a9; }</style><script> import device from '@system.device'; const defaultBtnBg="#f01f1f"; const defaultBtnFontSize=32; const defaultBtnTxtColor="#dcdcdc"; module.exports = { props: { // Ban disabled: { type: Boolean, default: false }, identity:{ type: String, default: '0', }, // Whether to turn off automatically autoClose: { type: Boolean, default: true }, // Slide the default distance threshold: { type: Number, default: 30 }, // Left button content leftOptions: { type: Array, default() { return [] } }, // Button content on the right rightOptions: { type: Array, default() { return [] } } }, data: { movestartX: 0, lastMoveX:0, translateEndX: 0, leftbtnsWidth: 0, rightbtnsWidth: 0, deviceLogicWidth:750, isLeftOpened: false, isRightOpened: false }, computed: { containerStyle() { console.info("computed containerStyle begin") var style = ''; let totalwidth=0; let leftwidth=0; this.leftOptions.forEach((item, index, array) => { console.info("computed item="+JSON.stringify(item)); leftwidth+=item.style.btnwidth; }) this.rightOptions.forEach((item, index, array) => { totalwidth+=item.style.btnwidth; }) totalwidth=totalwidth+this.deviceLogicWidth+leftwidth; console.info("computed totawidth="+totalwidth+", left width="+leftwidth); style += 'width:' + totalwidth + 'px;' style += 'transform: translateX(-' + leftwidth + 'px);' return style; } }, calBtnBgColor(color){ if(color!==undefined){ return color; } return defaultBtnBg; }, calBtnFontSize(size){ if(size!==undefined){ return size; } return defaultBtnFontSize; }, calBtnTxtColor(color){ if(color!==undefined){ return color; } return defaultBtnTxtColor; }, onInit() { console.info("oninit()"); this.$on('closeSwipeItem', this.closeFromParent); setTimeout(() => { this.calWidth(); }, 500); }, calWidth() { this.calLeftBtnsWidth(); this.calRightBtnsWidth(); }, calLeftBtnsWidth() { var that = this; this.$element('leftbtns').getBoundingClientRect({ success(res) { let msg = JSON.stringify(res); console.log('calLeftBtnsWidth Current coordinates :' + msg); // that.leftbtnsWidth = res.width; that.convertRealPx(true, res.width); }, fail() { console.log('calBoxWidth Acquisition failure '); }, complete() { console.log('calBoxWidth complete') } }) }, calRightBtnsWidth() { var that = this; this.$element('rightbtns').getBoundingClientRect({ success(res) { let msg = JSON.stringify(res); console.log('calRightBtnsWidth Current coordinates :' + msg); // that.rightbtnsWidth = res.width; that.convertRealPx(false, res.width); }, fail() { console.log('calBoxWidth Acquisition failure '); }, complete() { console.log('calBoxWidth complete') } }) }, convertRealPx(isLeftWidth, data) { var d = device.getInfoSync(); console.info("calBannerPostion1 d= " + JSON.stringify(d)); // Get the height and width of the visible window in the page , This value does not include the title bar and status bar heights let windowWidth = d.windowWidth; //logicWidth Corresponding manifest.json File settings designWidth value , The default is 750 let logicWidth = d.windowLogicWidth; let result = data * 1.0 * windowWidth / logicWidth; if (isLeftWidth) { this.leftbtnsWidth = result; } else { this.rightbtnsWidth = result; } }, dealTouchStart: function (e) { if (this.disabled) { return; } this.movestartX = e.touches[0].clientX; console.info("dealTouchStart movestartX="+this.movestartX); }, dealTouchMove: function (e) { if (this.disabled) { return; } let moveX = e.touches[0].clientX; let dis = moveX - this.movestartX; console.info("dealTouchMove moveX= " + moveX + ", dis=" + dis); if (Math.abs(dis) < this.threshold) { return; } if (dis > 0) { // Slide the button on the left right to call out or hide the button on the right to restore the initial state if (this.isRightOpened) { // Hide the button on the right , Restore to initial state this.animate(dis-this.rightbtnsWidth, dis); } else { // Slide right , Exhale the button on the left if (this.leftbtnsWidth > 0) { if (!this.isLeftOpened) { console.info("begin to show the left buttons"); this.animate(dis, dis); } } } } else if (dis < 0) { console.info("dealTouchMove left this.isLeftOpened=" + this.isLeftOpened); if (this.isLeftOpened) { // Slide slowly to hide the left button this.animate(this.leftbtnsWidth + dis, dis); } else { // Call out the button on the right if (this.rightbtnsWidth > 0) { if (!this.isRightOpened) { console.info("dealTouchMove begin to show the right buttons"); this.animate(dis, dis); } } } } }, dealTouchEnd: function (e) { if (this.disabled) { return; } let endX = e.changedTouches[0].clientX; let dis = endX - this.movestartX; if (Math.abs(dis) < this.threshold) { return; } console.info("dealTouchEnd dis=" + dis + ", endX=" + endX + ", isLeftOpened=" + this.isLeftOpened + ",isRightOpened=" + this.isRightOpened); if (dis > 0) { // Slide to the right if (this.isRightOpened) { // Hide the right button this.animate(dis - this.rightbtnsWidth, 0); this.isRightOpened = false; this.$emit('swipestatechange', {params: {"isOpened":false}}); } else { if (!this.isLeftOpened) { // Exhale the left button , Display the left button completely ; if (this.leftbtnsWidth > 0) { this.animate(dis, this.leftbtnsWidth); this.isLeftOpened = true; this.$emit('swipestatechange', {params: {"isOpened":true}}); } } } } else if (dis < 0) { // Slide left if (this.isLeftOpened) { // Hide the left button this.animate(this.leftbtnsWidth + dis, 0); this.isLeftOpened = false; this.$emit('swipestatechange', {params: {"isOpened":false}}); } else { if (this.rightbtnsWidth > 0 && !this.isRightOpened) { // Call out the right button , Display the right button completely this.animate(dis, -this.rightbtnsWidth); this.isRightOpened = true; this.$emit('swipestatechange', {params: {"isOpened":true}}); } } } }, animate(value1, value2) { console.info("aninate translateX from: " + value1 + ", to:" + value2); let cmp = this.$element('swipe_item'); var options = { duration: 300, easing: 'linear', delay: 0, fill: 'forwards' } console.info("dealTouchMove value2=" + value2); var frames = [ { transform: { translateX: value1, } }, { transform: { translateX: value2, } }]; var animation = cmp.animate(frames, options); animation.play(); animation.onfinish = function () { console.log("animation onfinish"); } animation.oncancel = function () { console.log("animation oncancel"); } }, btnsClick: function(index,direction,btnValue) { console.info("swipe.ux item click direction="+direction); this.$emit('swipebtnclick', {params: {"clickIndex":index,"position":direction,"btnValue":btnValue}}); // Button close if(direction=='left'){ this.animate(this.leftbtnsWidth, 0); this.isLeftOpened = false; }else{ this.animate( - this.rightbtnsWidth, 0); this.isRightOpened = false; } this.$emit('swipestatechange', {params: {"isOpened":false}}); }, close:function() { if(this.isLeftOpened){ // close this.animate(this.leftbtnsWidth, 0); this.isLeftOpened = false; this.$emit('swipestatechange', {params: {"isOpened":false}}); }else if(this.isRightOpened){ // close this.animate( - this.rightbtnsWidth, 0); this.isRightOpened = false; this.$emit('swipestatechange', {params: {"isOpened":false}}); }else{ // The middle part responds to its own click event this.$emit('centerclick', {params: {}}); } }, closeFromParent:function(e) { console.info("closeFromParent e="+JSON.stringify(e)); if(!this.autoClose){ return; } // The newly opened operation bar is not closed , Others are only closed let excludeCloseId=e.detail.exclude; if(excludeCloseId==this.identity){ return; } if(this.isLeftOpened){ // close this.animate(this.leftbtnsWidth, 0); this.isLeftOpened = false; }else if(this.isRightOpened){ // close this.animate( - this.rightbtnsWidth, 0); this.isRightOpened = false; } }, dealClickCenter: function() { console.info("dealClickCenter"); this.close(); }, }</script> page main.ux<import name="swipeitem" src="../Component/swipe_item.ux"></import><template> <!-- Only one root node is allowed in template. --> <div class="container"> <div class="section"> <text class="sec_txt"> Only on the left </text> </div> <swipeitem identity='111' left-options="{{leftBtns}}" @swipebtnclick="swipeItemClick" @swipestatechange="swipeItemChange('111')"> <text> Only the left button </text> </swipeitem> <div class="section"> <text class="sec_txt"> Only the right </text> </div> <swipeitem identity='112' right-options="{{rightBtns}}" @swipebtnclick="swipeItemClick" @swipestatechange="swipeItemChange('112')"> <text> Only the right button </text> </swipeitem> <div class="section"> <text class="sec_txt"> Blend scrolling </text> </div> <swipeitem identity='113' right-options="{{rightBtns}}" left-options="{{leftBtns}}" @swipebtnclick="swipeItemClick" @swipestatechange="swipeItemChange('113')"> <text> There are mixed scrolls on both sides </text> </swipeitem> <div class="section"> <text class="sec_txt"> Do not scroll left or right </text> </div> <swipeitem disabled="{{disabled}}" left-options="{{leftBtns}}" right-options="{{rightBtns}}" @swipebtnclick="swipeItemClick"> <text> Do not scroll left or right </text> </swipeitem> <div class="section"> <text class="sec_txt">div list </text> </div> <div class="swipelist" id="swiplist"> <swipeitem identity="{{item.id}}" auto-close={{isautoclose}} right-options="{{item.options}}" for="(index,item) in swipeList" @swipestatechange="listSwipeItemChange(index)" @swipebtnclick="listSwipeItemClick(index)" @centerclick="listCenterItemClick(index)"> <text onclick="clickText">{{item.content}}</text> </swipeitem> </div> </div></template><style> .container { flex-direction: column; width: 100%; } .section { background-color: #f5f5f5; height: 100px; width: 100%; border: 1px solid #f5f5f5; } .swipelist { flex-direction: column; } .istItemStyle { width: 1300px; } .liststyle { flex-direction: column; } .sec_txt { font-size: 32px; font-weight: 600; margin-left: 25px; margin-top: 10px; }</style><script> import prompt from '@system.prompt'; module.exports = { data: { isautoclose:true, leftBtns: [], disabled: true, rightBtns: [], unstyleleftBtns: [], unstylerightBtns: [], swipeList: [] }, onInit: function () { let btn1 = { "txt": " Roof placement ", "style": { "backgroundColor": "#00bfff", "txtColor": "#dcdcdc", "fontsize": 30, "btnwidth": 150 } }; let btn2 = { "txt": "ok", "style": { "backgroundColor": "#00bfff", "txtColor": "#dcdcdc", "fontsize": 30, "btnwidth": 200 } }; let btn3 = { "txt": " Cancel topping ", "style": { "backgroundColor": "#f01f1f", "txtColor": "#dcdcdc", "fontsize": 30, "btnwidth": 150 } }; let btn4 = { "txt": "cancel", "style": { "backgroundColor": "#00bfff", "txtColor": "#dcdcdc", "fontsize": 30, "btnwidth": 180 } }; let unstylebtn1 = { "txt": " Roof placement ", "style": { "btnwidth": 230 } }; let unstylebtn2 = { "txt": "ok", "style": { "btnwidth": 200 } }; let unstylebtn3 = { "txt": " Cancel topping ", "style": { "btnwidth": 150 } }; let unstylebtn4 = { "txt": "cancel", "style": { "txtColor": "#ff9900", "fontsize": 30, "btnwidth": 150 } }; this.leftBtns.push(btn1); this.leftBtns.push(btn2); this.rightBtns.push(btn3); this.rightBtns.push(btn4); this.unstyleleftBtns.push(unstylebtn1); this.unstyleleftBtns.push(unstylebtn2); this.unstylerightBtns.push(unstylebtn3); this.unstylerightBtns.push(unstylebtn4); }, onReady(options) { this.swipeList = [{ options: [{ txt: ' add to ', style: { backgroundColor: 'rgb(255,58,49)', txtColor: "#dcdcdc", fontsize: 36, btnwidth: 150 } }], id: '10', content: 'item1' }, { id: '11', options: [{ txt: ' add to ', style: { backgroundColor: 'rgb(255,58,49)', txtColor: "#dcdcdc", fontsize: 30, btnwidth: 150 } }, { txt: ' Delete ', style: { backgroundColor: 'rgb(255,58,49)', txtColor: "#dcdcdc", fontsize: 30, btnwidth: 150 } } ], content: 'item2' }, { id: '12', options: [{ txt: ' Roof placement ', style: { backgroundColor: 'rgb(255,58,49)', txtColor: "#dcdcdc", fontsize: 30, btnwidth: 150 } }, { txt: ' Mark as read ', style: { backgroundColor: 'rgb(255,58,49)', txtColor: "#dcdcdc", fontsize: 30, btnwidth: 150 } }, { txt: ' Delete ', style: { backgroundColor: 'rgb(255,58,49)', txtColor: "#dcdcdc", fontsize: 30, btnwidth: 150 } } ], content: 'item3' } ] }, listSwipeItemClick: function (index, e) { console.info("main swipeItemClick e:" + JSON.stringify(e) + ",index=" + index); let position = e.detail.params.position; // // let index = e.detail.params.clickIndex; // let itemListId = e.detail.params.itemListIndex; let btnValue = e.detail.params.btnValue; let msg = ''; if (position == 'left') { // msg=' Click on the left ${e.detail.params.btnValue} Button ' ; msg = ' Click on the left ' + btnValue + ' Button '; } else { msg = ' Click on the right ' + btnValue + ' Button '; } prompt.showToast({ message: msg, duration: 2000, gravity: 'center' }) if (btnValue == " add to ") { console.info("begin to add ") this.addSwipteItem(); } else if (btnValue == " Delete ") { this.delSwipteItem(index); } }, addSwipteItem: function () { this.swipeList.push({ id: new Date().getTime(), content: ' newly added ' + new Date().getTime(), options: [{ txt: ' Roof placement ', style: { fontsize: 30, btnwidth: 150 } }, { txt: ' Mark as read ', style: { backgroundColor: 'rgb(254,156,1)', fontsize: 30, btnwidth: 150 } }, { txt: ' Delete ', style: { backgroundColor: 'rgb(255,58,49)', fontsize: 30, btnwidth: 150 } } ], }); }, delSwipteItem: function (index) { var that = this; prompt.showDialog({ title: ' Tips ', message: ' Whether or not to delete ', buttons: [ { text: ' determine ', color: '#33dd44' }, { text: ' Cancel ', color: '#33dd44' }], success: function (data) { console.log("delSwipteItem showDialog handling callback data:" + JSON.stringify(data)); if (data.index == 0) { //delete that.swipeList.splice(index, 1); } }, fail: function (data, code) { console.log("handling fail, code = " + code); } }) }, swipeItemClick: function (e) { console.info("main swipeItemClick e:" + JSON.stringify(e)); let position = e.detail.params.position; let btnValue = e.detail.params.btnValue; let msg = ''; if (position == 'left') { // msg=' Click on the left ${e.detail.params.btnValue} Button ' ; msg = ' Click on the left ' + btnValue + ' Button '; } else { msg = ' Click on the right ' + btnValue + ' Button '; } prompt.showToast({ message: msg, duration: 2000, gravity: 'center' }) }, clickText: function () { console.info("click text"); prompt.showToast({ message: 'click text', duration: 2000, gravity: 'center' }) }, listCenterItemClick: function (index, e) { console.info("main listCenterItemClick e:" + JSON.stringify(e) + ",index=" + index); prompt.showToast({ message: 'click text', duration: 2000, gravity: 'center' }) }, listSwipeItemChange: function (index, e) { console.info("main listSwipeItemChange e:" + JSON.stringify(e) + ",index=" + index); this.$broadcast('closeSwipeItem', { 'exclude': this.swipeList[index].id }); }, swipeItemChange: function(id,e) { console.info("main swipeItemChange e:" + JSON.stringify(e)+",id="+id); this.$broadcast('closeSwipeItem', { 'exclude': id }); }, }</script>
For more technical articles , Welcome to visit https://developer.huawei.com/consumer/cn/forum/?ha_source=zzh
边栏推荐
- [南京大学]-[软件分析]课程学习笔记(一)-introduction
- QT charts use (rewrite qchartview to realize some custom functions)
- [Nanjing University] - [software analysis] course learning notes (I) -introduction
- Greenplum6.x重新初始化
- 如何在图片的目标中添加目标的mask
- xray的简单使用
- Nanjing commercial housing sales enabled electronic contracts, and Junzi sign assisted in the online signing and filing of housing transactions
- Merge sort and non comparison sort
- [machine learning] watermelon book data set_ data sharing
- 23 Chengdu instrument customization undertaking_ Discussion on automatic wiring method of PCB in Protel DXP
猜你喜欢
南京商品房买卖启用电子合同,君子签助力房屋交易在线网签备案
Greenplum 6.x version change record common manual
let const
JS的操作
[Nanjing University] - [software analysis] course learning notes (I) -introduction
A bug using module project in idea
Data type - integer (C language)
[step on the pit] Nacos registration has been connected to localhost:8848, no available server
【MySQL】数据库进阶之触发器内容详解
Rapid integration of authentication services - harmonyos platform
随机推荐
POJ - 3784 running medium
[Yugong series] February 2022 U3D full stack class 007 - production and setting skybox resources
Speaking of a software entrepreneurship project, is there anyone willing to invest?
Frequently Asked Coding Problems
[Chongqing Guangdong education] audio visual language reference materials of Xinyang Normal University
ncs成都新电面试经验
Leetcode 1984. Minimum difference in student scores
注解@ConfigurationProperties的三种使用场景
2-3查找樹
Required String parameter ‘XXX‘ is not present
POJ - 3784 Running Median(对顶堆)
Arm GIC (IV) GIC V3 register class analysis notes.
使用AGC重签名服务前后渠道号信息异常分析
数据分析方法论与前人经验总结2【笔记干货】
调用华为游戏多媒体服务的创建引擎接口返回错误码1002,错误信息:the params is error
Three series of BOM elements
Download and install orcale database11.2.0.4
详解华为应用市场2022年逐步减少32位包体上架应用和策略
[step on the pit] Nacos registration has been connected to localhost:8848, no available server
National SMS center number inquiry