The Mint-ui component library is used in mobile development, and there are two components, Popup component and Datetime Picker, which have scrollability penetration problems. The latest version of the official document does not solve this problem.
Restore the phenomenon
Official address
Scan the code on your mobile phone to view demos, and view example demonstrations of the two components Popup components and Datetime.
Cause of the problem
HTML5 touch event touchmove event: triggers continuously when the finger slides on the screen
So when the popup layer of the component Popup component and the Datetime Picker is activated, the continuous sliding up and down while the content is selected by the bounce layer will trigger the event
Solution
Block the touchmove event of the body after the pop-up layer appears, and remove the block event after the bullet layer disappears
Solution to using mint-ui component library
Popup Components
// Official example
<mt-popup v-model="popupVisible" position="bottom"> ... </mt-popup>
// Solution: by listening to the popupVisible variable, the touchMove event of the bode node appears after the popup window appears, and the touchMove event of the body node is restored after the popup window disappears.
const handler = function(e) { (); } // In the vue instancewatch: { popupVisible: function (val) { if(val) { ('body')[0].addEventListener('touchmove', , { passive: false }); } else { ('body')[0].addEventListener('touchmove', , { passive: false }); } } }
Datetime Picker
// Official example
<mt-datetime-picker ref="picker" type="time" v-model="pickerValue"> </mt-datetime-picker>
// Solution: This component is quite a pitfall. Since Datetime Picker does not provide popup display and hidden binding variables, we do not use the method of solving popup to solve the problem. We can only solve the problem by opening the event, confirming the event, canceling the event, and clicking the masked popup window to disappear. The official attribute method only supports confirming events and opening events. There is no callback function for canceling the event plain text, and it does not support clicking on the masked pop-up window to disappear, so it is very tricky.
<mt-datetime-picker ref="picker" type="time" v-model="pickerValue" @confirm="confirm"> </mt-datetime-picker> const handler = function(e) { (); }
// In the vue instance
methods: { openPicker() { // Open the event ('body')[0].addEventListener('touchmove', , { passive: false }); this.$(); }, confirm() { // Confirm the event ('body')[0].addEventListener('touchmove', , { passive: false }); } }
At this time, there is also a cancel callback and a masked click event. Then look at the source code, the mint-ui source code supports cancel callback events. In addition, the surprise is that after version 2.0, the visible-change event and closeOnClickModal attribute (portal) were added to the Datetime picker component, but the official documentation still did not update these attributes. The above problem is solved very well now.
Moreover, with the visible-change event, you can solve it without following the above idea. The component source code is as follows:
props: { ..., closeOnClickModal: { type: Boolean, default: true } }, watch: { ..., visible(val) { this.$emit('visible-change', val); } }, ... <span class="mint-datetime-action mint-datetime-cancel" @click="visible = false;$emit('cancel')">{{ cancelText }}</span>
Directly a visible-change method to solve it
<mt-datetime-picker ref="picker" type="time" v-model="pickerValue" @confirm="confirm" @visible-change=""handleValueChange> </mt-datetime-picker> const handler = function(e) { (); } // In the vue instancemethods: { handleValueChange: function (val) { if(val) { ('body')[0].addEventListener('touchmove', , { passive: false }); } else { ('body')[0].addEventListener('touchmove', , { passive: false }); } } }
The above method can solve the pitfalls encountered by the project, but each page uses the component Popup component and the Datetime Picker, which requires adding this code. When there are multiple Popup components on the page, you need to listen to multiple variables.
Better solution (The above method also has similar solutions online, and I have added the visible-change solution myself)
It is too troublesome to solve the problem in the project as above, so I thought of a solution that is better experienced. Because the appearance and disappearance of the bullet layer will trigger component updates, I thought of registering a command v-roll globally and using the command componentUpdated hook to implement this function. The code is as follows
// Global registration instructionconst handler = (e) => { (); }; ('roll', { componentUpdated(el, binding) { if () { ('body')[0].addEventListener('touchmove', handler, { passive: false }); } else { ('body')[0].removeEventListener('touchmove', handler, { passive: false }); } } });
This simplifies a lot of code, and other developers only need to add a v-roll instruction to the corresponding component when using it.
// How to handle popup component<mt-popup v-model="popupVisible" v-roll:visible=popupVisible> ... </mt-popup> // mt-datetime-picker component processing method<mt-datetime-picker ref="datePicker" v-model="date" @visible-change="handleVisibleChange" v-roll:visible=pVisible ...> </mt-datetime-picker> ... data: { pVisible: false }, methods: { handleVisibleChange (isVisible) { = isVisible; } }
Then I encountered a pitfall. When there are multiple components, Popup components and Datetime Picker usage instructions on the same view page, the instructions will be triggered collectively. Therefore, it will overwrite each other, such as opening the A bullet layer to block the touchMove event on the page, but another popuu component also triggers the hook function and unblocks the touchMove event, resulting in no effect.
componentUpdated: Called after the VNode and its child VNode of the component where the directive is located. // My current understanding here is that the view interface node is updated due to the appearance and disappearance of the bullet layer, so the hook bound to the v-roll instruction of other nodes is also triggered
Solution:For multiple components using multiple components in a view, pass the array type to the instruction
// Global registration instructionconst handler = (e) => { (); }; ('roll', { componentUpdated(el, binding) { if ( instanceof Array) { const visible = (e => e); // When one of the variables in the control layer of the view is true, the touchmove event can be blocked if (visible) { ('body')[0].addEventListener('touchmove', handler, { passive: false }); } else { ('body')[0].removeEventListener('touchmove', handler, { passive: false }); } } else if (typeof === 'boolean') { if () { ('body')[0].addEventListener('touchmove', handler, { passive: false }); } else { ('body')[0].removeEventListener('touchmove', handler, { passive: false }); } } } }); // How to handle popup component<mt-popup v-model="popupVisible" v-roll:visible=[popupVisible, pVisible]> ... </mt-popup> // mt-datetime-picker component processing method<mt-datetime-picker ref="datePicker" v-model="date" @visible-change="handleVisibleChange" v-roll:visible=[popupVisible, pVisible] ...> </mt-datetime-picker> ... data: { pVisible: false }, methods: { handleVisibleChange (isVisible) { = isVisible; } }
At present, mint-ui has not fixed this problem, so we will use the above solution to solve it. I planned to change the source code at the beginning, but it was not realistic, because I might need to update the mint-ui version in the future. You can also help check whether there are any pitfalls in the above solution.
Supplementary knowledge:There will be scrolling penetration problems on ios when using mint-ui's date plugin in Vue
Problem: When selecting a date to slide up and down on iOS, the entire page will scroll accordingly, and Android is normal
The solution is to prohibit the default scrolling mechanism of the page when the date pop-up layer appears, and to unblock the default scrolling mechanism of the page when the date pop-up layer disappears.
1. Call the date component
<div class="datePicker" style="z-index: 9999"> <mt-datetime-picker type="date" ref="picker" v-model="nowTime" year-format="{value} Year" month-format="{value} moon" date-format="{value} day" @confirm="handleConfirm" :startDate="startDate" :endDate="endDate" > </mt-datetime-picker> </div>
2. Set up the listening function
data () { return { birthday:"", //Date of Birth startDate: new Date('1952'), endDate:new Date(), nowTime:'1992-09-15', /*---------------------------*/ handler:function(e){();} } }, methods:{ /*Solve the problem of mutual influence of iPhone page hierarchy*/ closeTouch:function(){ ("body")[0].addEventListener('touchmove', ,{passive:false});//Block default events ("closeTouch haved happened."); }, openTouch:function(){ ("body")[0].removeEventListener('touchmove', ,{passive:false});//Open the default event ("openTouch haved happened."); }, }
Then listen, call the corresponding method when the pop-up window disappears
// Listen to propertieswatch:{ signReasonVisible:function(newvs,oldvs){// There is no callback function when picker is closed, so listen to this property instead if(newvs){ (); }else{ (); } } },
The following is the processing of datetime-picker: (openPicker1 is the event that triggers the open selector, handleConfirm (data) is the callback function after the date is selected)
openPicker () { this.$(); ();//Close the default event }, handleConfirm (data) { let date = moment(data).format('YYYY-MM-DD') = date; ();//Open the default event },
Then this problem was solved!
The above article solves the problem of scrolling penetration of the Mint-ui framework Popup and Datetime Picker components is all the content I share with you. I hope you can give you a reference and I hope you can support me more.