浏览器探究——回退和前进

前进:

在菜单中点击前进功能主线程会执行BrowserActivity.onOptionsItemSelected,它会调用Controller.onOptionsItemSelected,在处理该菜单项时执行如下语句getCurrentTab().goForward();入口点很明确,就是调用了当前tab的goForward函数。

Tab.goForward调用了主WebView的goForward

WebView.goForward

/**     * Go forward in thehistory of this WebView.     */该函数内先执行了一句checkThread(),这里额外说一句该函数,该函数怎么检查的线程?其实就是判断下当前线程的looper是不是main looper,如果不是就报异常。而且该函数是个静态函数。该函数在WebView的很多地方都有调用,基本上每个WebView的函数都调了,也就是要求WebView这个控件必须在主线程中运行啦。

之后调用WebView.goBackOrForwardImpl。这个函数是回退很前进的统一实现函数。另外有个类似的函数叫WebView.goBackOrForward,其实实现是一样的。

  *Go to the history item that is the number of steps away from     * the current item. Steps is negative ifbackward and positive     * ifforward.     * @param steps The number ofsteps to take back or forward in the back    *              forward list.     */可见回退还是前进,就是通过参数step来决定的。这样看来回退也会调用到该函数。

的确,回退是调用Tab.goBack,进而调用WebView.goBack进而调用WebView.goBackOrForwardImpl,只是参数不同而已。

继续看WebView.goBackOrForward,这里首先调用了WebView.clearHelpers

/**     * Called to clearstate when moving from one page to another, or changing     * in some other way that makes elementsassociated with the current page     *(such as WebTextView or ActionModes) no longer relevant.     */这个函数还是很有用的,他做了很多所谓的清除的工作,包括界面上的和一些状态上的。此处不细看。

接下来是我们熟悉的向WebViewCoreThread线程发消息的流程了。发送GO_BACK_FORWARD消息,WebViewCoreThread线程收到消息后,执行BrowserFrame.goBackOrForward,BrowserFrame.goBackOrForward会调用jni函数nativeGoBackOrForward,该函数对应c层webkit/Source/WebKit/android/jni里的函数。

从c层的JNI函数出来,会回调WebBackForwardList.setcurrentIndex

/**     * Set the new historyindex.     * @param newIndex The newhistory index.     */

这个jni回调对应webkit/Source/WebKit/android/jni/WebHistory.cpp

WebBackForwardList.seturrentIndex是BrowserFame.nativeGoBackOrForward执行是回调上来的函数,所以当前还处于WebViewCoreThread线程中,该函数会通过CallbackProxy发消息给主线程,发HISTORY_INDEX_CHANGE消息。主线程接收到该消息后,执行Tab的WebBackForwardListClient的onIndexChanged。

WebBackForwardListClient

/** * Interface to receive notificationswhen items are added to the * {@link WebBackForwardList}. * {@hide} */

在Tab构造函数中被创建。这个onIndexChanged的处理略过。总之是通过回调把更新BackForwordList索引的事件传了出来,并发送到了主线程中进行了处理。

接着,BrowserFrame.nativeGoBackOrForward从c层的JNI函数出来,会回调BrowserFrame.handleUrl函数。此时回调的参数url已经是待加载的url了,即新的Url了。

/**     * This method iscalled by WebCore to check whether application     * wants to hijack url loading     */

这个函数就是个hijack函数,做一些拦截处理。如果没什么可拦截的,那么这个函数什么也不做的返回。

接着,BrowserFrame.nativeGoBackOrForward从c层的JNI函数出来会回调BrowserFrame.loadStarted。此时回调的参数url已经是待加载的url了,即新的Url了。

 

/**     * native callback     * Indicates the beginning of a newload.     * This method will be calledonce for the main frame.     */

还是老流程了,通过CallbackProxy发送PAGE_STARTED消息给主线程,其中参数包含一个url和一个Bitmap的图标,应该就是网站的logo了。主线程接收后执行Tab的WebViewClient.onPageStarted。该函数对执行WebViewController.onPageStarted,这个WebViewController就是Controller,由于Controller是继承WebViewController接口的。

WebViewController.onPageStarted这个函数在loadurl那节讲了,这里补充一点,里面调用了maybeUpdateFavicon,这个函数会更新bookmark数据库的favicon。传入的Bitmap参数在这里被用到。之后WebViewClient.onPageStarted会执行WebViewClient.updateBookmarkedStatus。即WebViewClient.onPageStarted操作会更新bookmark数据库的。

继续回到BrowserFrame.nativeGoBackOrForward,从c层的JNI函数出来会回调BrowserFarme.setProgress。

/**     * Set the progress forthe browser activity.  Called by native code.     * Uses a delay so it does not happen toooften.     * @param newProgress An intbetween zero and one hundred representing    *                    the currentprogress percentage of loading the page.    */

这个函数的实现略去,主要是会更新UI等状态。

接下来的操作就跟lordUrl的一样了。

禁用浏览器前进后退按钮,通常并不是真正意义上的“禁用”,而是通过操作浏览器的历史记录栈来实现一种“无法回退”的效果。以下是几种常见的实现方式: ### 使用 `history.pushState` `popstate` 事件 通过向浏览器历史栈中不断推送新的状态,可以防止用户通过“前进”或“后退”按钮导航到之前的页面。示例代码如下: ```javascript // 向历史栈中添加当前页面状态 history.pushState(null, null, location.href); // 监听 popstate 事件,当用户尝试前进或后退时再次推送状态 window.addEventListener('popstate', function () { history.pushState(null, null, location.href); }); ``` 该方法通过不断添加新的历史状态,使用户无法通过浏览器的导航按钮返回到之前的页面,从而在视觉上实现“禁用”效果。 ### 使用 `history.replaceState` 替换当前状态 如果希望替换当前页面的历史记录条目,而不是添加新的条目,可以使用 `history.replaceState`: ```javascript // 替换当前页面的历史记录条目 history.replaceState(null, null, location.href); // 监听 popstate 事件,确保用户无法前进或后退 window.onpopstate = function () { history.replaceState(null, null, location.href); }; ``` 此方法可以防止用户通过浏览器前进或后退按钮导航到其他页面,同时不会在历史记录中留下多个条目。 ### 在 Vue 3 中实现禁用浏览器导航 在 Vue 3 的 `script setup` 模式下,可以结合 `ref` 生命周期钩子 `onBeforeUnmount` 来管理状态并监听 `popstate` 事件: ```vue <template> <button @click="disableNavigation">点击禁用前进或后退</button> </template> <script setup> import { ref, onBeforeUnmount } from 'vue'; const isNavigationDisabled = ref(false); const disableNavigation = () => { window.history.pushState(null, '', window.location.href); isNavigationDisabled.value = true; window.addEventListener('popstate', handlePopState); }; const handlePopState = () => { if (isNavigationDisabled.value) { window.history.pushState(null, '', window.location.href); } }; onBeforeUnmount(() => { window.removeEventListener('popstate', handlePopState); }); </script> ``` 该方法在用户点击按钮后,将禁用浏览器前进后退功能,并在组件卸载时清理事件监听器,防止内存泄漏。 ### 注意事项 - 这些方法并不能真正“禁用”浏览器按钮,而是通过修改历史记录来模拟禁用效果。 - 用户仍可以通过关闭标签页、刷新页面或使用其他浏览器功能绕过限制。 - 不建议在所有场景中使用此类功能,可能会影响用户体验可访问性。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值