文(Vue實戰——優化新聞列表頁模塊化抽離封裝axios)分享到了優化了新聞列表頁,可以很美觀的查看新聞列表了,但是還沒有實現新聞詳情,本節將介紹如何通過Router的動態參數傳遞實現新聞詳情頁,同時實現v-html里的樣式穿透。本項目git地址:
https://gitee.com/vuejslearn/news-list.git
從git上拉下最新代碼,在views里添加新頁面:newsDetail.vue:
<template> </template> <script> export default { name: 'newsDetail' } </script> <style scoped> </style>
修改路由文件,在路由數組最后面添加詳情頁的路由:
{ path: '/detail', name: 'newsDetail', component: ()=> import(/* webpackChunkName: "about" */ '../views/newsDetail.vue'), meta: { showHeader: true, requiresAuth: true } }
修改新聞列表頁,添加goDetail方法:
goDetail (content) { this.$router.push({ path: '/detail', query: { content: content } }) }
同時在新聞標題、圖片上添加
@click="goDetail(news.content)"
如圖:
這樣,當點擊標題、圖片時,都可以跳轉到新聞詳情頁。
這里所用的就是編程試的路由動態參數傳遞了,
this.$router.push({ path: '/detail', query: { content: content } })
這樣的路由,最后形成的url地址:
/detail?content=xxxxxxx
如果想實現路徑的動態參數,可以這么做:
router.push({ name: 'detail', params: { '123' }})
這樣實現的url就是:
/detail/123
ok,現在來看看詳情頁的樣子吧:
我們看到,雖然顯示出來了,也居中顯示,但是圖片怎么明顯多出來一截呢?我們調整樣式,讓它回去,可是這個樣式是在html里的,也就是說,我們的模板是這樣實現的:
這個是v-html的,是動態傳遞的,我們改怎么對這類的樣式進行修改了呢?
網上有人說需要去掉scoped,也就是把<style>里的scoped去掉,但是那樣css樣式就會公開,會很危險,有沒有別的辦法呢?答案是有的,使用“>>>”穿透符。具體:
這樣就會使圖片的樣式改變了,請看:
多出的一截已經沒有了。但是我們這種方法不能用在less上,也就是必須是純css代碼才能用哦。
原創不容易,鑒于本人水平有限,文中如有錯誤之處歡迎大家指正。以后我會持續發布vue實戰系列的文章,喜歡的朋友歡迎關注。
天來聊一個 JavaWeb 中簡單的話題,但是感覺卻比較稀罕,因為這個技能點,有的小伙伴們可能沒聽過!
說到 Web 請求參數傳遞,大家能想到哪些參數傳遞方式?
參數可以放在地址欄中,不過地址欄參數的長度有限制,并且在有的場景下我們可能不希望參數暴漏在地址欄中。參數可以放在請求體中,這個沒啥好說的。
小伙伴們試想這樣一個場景:
在一個電商項目中,有一個提交訂單的請求,這個請求是一個 POST 請求,請求參數都在請求體中。當用戶提交成功后,為了防止用戶刷新瀏覽器頁面造成訂單請求重復提交,我們一般會將用戶重定向到一個顯示訂單的頁面,這樣即使用戶刷新頁面,也不會造成訂單請求重復提交。
大概的代碼就像下面這樣:
@Controller
public class OrderController {
@PostMapping("/order")
public String order(OrderInfo orderInfo) {
//其他處理邏輯
return "redirect:/orderlist";
}
}
這段代碼我相信大家都懂吧!如果不懂可以看看松哥錄制的免費的 SpringMVC 入門教程(硬核!松哥又整了一套免費視頻,搞起!)。
但是這里有一個問題:如果我想傳遞參數怎么辦?
如果是服務器端跳轉,我們可以將參數放在 request 對象中,跳轉完成后還能拿到參數,但是如果是客戶端跳轉我們就只能將參數放在地址欄中了,像上面這個方法的返回值我們可以寫成:return "redirect:/orderlist?xxx=xxx";,這種傳參方式有兩個缺陷:
那該怎么辦?還有辦法傳遞參數嗎?
有!這就是今天松哥要和大家介紹的 flashMap,專門用來解決重定向時參數的傳遞問題。
在重定向時,如果需要傳遞參數,但是又不想放在地址欄中,我們就可以通過 flashMap 來傳遞參數,松哥先來一個簡單的例子大家看看效果:
首先我們定義一個簡單的頁面,里邊就一個 post 請求提交按鈕,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/order" method="post">
<input type="submit" value="提交">
</form>
</body>
</html>
然后在服務端接收該請求,并完成重定向:
@Controller
public class OrderController {
@PostMapping("/order")
public String order(HttpServletRequest req) {
FlashMap flashMap = (FlashMap) req.getAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE);
flashMap.put("name", "江南一點雨");
return "redirect:/orderlist";
}
@GetMapping("/orderlist")
@ResponseBody
public String orderList(Model model) {
return (String) model.getAttribute("name");
}
}
首先在 order 接口中,獲取到 flashMap 屬性,然后存入需要傳遞的參數,這些參數最終會被 SpringMVC 自動放入重定向接口的 Model 中,這樣我們在 orderlist 接口中,就可以獲取到該屬性了。
當然,這是一個比較粗糙的寫法,我們還可以通過 RedirectAttributes 來簡化這一步驟:
@Controller
public class OrderController {
@PostMapping("/order")
public String order(RedirectAttributes attr) {
attr.addFlashAttribute("site", "www.javaboy.org");
attr.addAttribute("name", "微信公眾號:江南一點雨");
return "redirect:/orderlist";
}
@GetMapping("/orderlist")
@ResponseBody
public String orderList(Model model) {
return (String) model.getAttribute("site");
}
}
RedirectAttributes 中有兩種添加參數的方式:
經過前面的講解,現在小伙伴們應該大致明白了 flashMap 的作用了,就是在你進行重定向的時候,不通過地址欄傳遞參數。
很多小伙伴可能會有疑問,重定向其實就是瀏覽器發起了一個新的請求,這新的請求怎么就獲取到上一個請求保存的參數呢?這我們就要來看看 SpringMVC 的源碼了。
首先這里涉及到一個關鍵類叫做 FlashMapManager,如下:
public interface FlashMapManager {
@Nullable
FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);
void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
}
兩個方法含義一眼就能看出來:
FlashMapManager 的實現類如下:
從這個繼承類中,我們基本上就能確定默認的保存介質時 session。具體的保存邏輯則是在 AbstractFlashMapManager 類中。
整個參數傳遞的過程可以分為三大步:
第一步,首先我們將參數設置到 outputFlashMap 中,有兩種設置方式:我們前面的代碼 req.getAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE) 就是直接獲取 outputFlashMap 對象然后把參數放進去;第二種方式就是通過在接口中添加 RedirectAttributes 參數,然后把需要傳遞的參數放入 RedirectAttributes 中,這樣當處理器處理完畢后,會自動將其設置到 outputFlashMap 中,具體邏輯在 RequestMappingHandlerAdapter#getModelAndView 方法中:
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
//省略...
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
可以看到,如果 model 是 RedirectAttributes 的實例的話,則通過 getOutputFlashMap 方法獲取到 outputFlashMap 屬性,然后相關的屬性設置進去。
這是第一步,就是將需要傳遞的參數,先保存到 flashMap 中。
第二步,重定向對應的視圖是 RedirectView,在它的 renderMergedOutputModel 方法中,會調用 FlashMapManager 的 saveOutputFlashMap 方法,將 outputFlashMap 保存到 session 中,如下:
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
HttpServletResponse response) throws IOException {
String targetUrl = createTargetUrl(model, request);
targetUrl = updateTargetUrl(targetUrl, model, request, response);
// Save flash attributes
RequestContextUtils.saveOutputFlashMap(targetUrl, request, response);
// Redirect
sendRedirect(request, response, targetUrl, this.http10Compatible);
}
RequestContextUtils.saveOutputFlashMap 方法最終就會調用到 FlashMapManager 的 saveOutputFlashMap 方法,將 outputFlashMap 保存下來。我們來大概看一下保存邏輯:
public final void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response) {
if (CollectionUtils.isEmpty(flashMap)) {
return;
}
String path = decodeAndNormalizePath(flashMap.getTargetRequestPath(), request);
flashMap.setTargetRequestPath(path);
flashMap.startExpirationPeriod(getFlashMapTimeout());
Object mutex = getFlashMapsMutex(request);
if (mutex != null) {
synchronized (mutex) {
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
allFlashMaps = (allFlashMaps != null ? allFlashMaps : new CopyOnWriteArrayList<>());
allFlashMaps.add(flashMap);
updateFlashMaps(allFlashMaps, request, response);
}
}
else {
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
allFlashMaps = (allFlashMaps != null ? allFlashMaps : new ArrayList<>(1));
allFlashMaps.add(flashMap);
updateFlashMaps(allFlashMaps, request, response);
}
}
其實這里的邏輯也很簡單,保存之前會給 flashMap 設置兩個屬性,一個是重定向的 url 地址,另一個則是過期時間,過期時間默認 180 秒,這兩個屬性在第三步加載 flashMap 的時候會用到。然后將 flashMap 放入集合中,并調用 updateFlashMaps 方法存入 session 中。
第三步,當重定向請求到達 DispatcherServlet#doService 方法后,此時會調用 FlashMapManager#retrieveAndUpdate 方法從 Session 中獲取 outputFlashMap 并設置到 Request 屬性中備用(最終會被轉化到 Model 中的屬性),相關代碼如下:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//省略...
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
//省略...
}
注意這里獲取出來的 outputFlashMap 換了一個名字,變成了 inputFlashMap,其實是同一個東西。
我們可以大概看一下獲取的邏輯 AbstractFlashMapManager#retrieveAndUpdate:
public final FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) {
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
if (CollectionUtils.isEmpty(allFlashMaps)) {
return null;
}
List<FlashMap> mapsToRemove = getExpiredFlashMaps(allFlashMaps);
FlashMap match = getMatchingFlashMap(allFlashMaps, request);
if (match != null) {
mapsToRemove.add(match);
}
if (!mapsToRemove.isEmpty()) {
Object mutex = getFlashMapsMutex(request);
if (mutex != null) {
synchronized (mutex) {
allFlashMaps = retrieveFlashMaps(request);
if (allFlashMaps != null) {
allFlashMaps.removeAll(mapsToRemove);
updateFlashMaps(allFlashMaps, request, response);
}
}
}
else {
allFlashMaps.removeAll(mapsToRemove);
updateFlashMaps(allFlashMaps, request, response);
}
}
return match;
}
這就是整個獲取 flashMap 的方法,整體來看還是非常 easy 的,并沒有什么難點。
好啦,今天就和小伙伴們分享了一下 SpringMVC 中的 flashMap,不知道大家有沒有在工作中用到這個東西?如果剛好碰到松哥前面所說的需求,用 FlashMap 真的還是蠻方便的。如果需要下載本文案例,小伙伴們可以在公眾號【江南一點雨】后臺回復 20210302,好啦,今天就和大家聊這么多~
天呢,暖寶給大家帶來javascript的歷險函數傳參,如果覺得好的話,動動手指關注暖夕H2,文末有彩蛋哦~~
javascript的參數:
上圖為示例代碼:
1.“num“,“value”為參數
2.在button按鈕中改變函數的值,只需要調用change()這個函數的的參數的值就行了,上圖示例為改變一個對象的寬度。
什么叫作對象?
比如上圖first就是一個對象,它的style為它的屬性。
什么就作字面量?
就是你在js里能夠看到的帶引號的值。
比如上文的‘width’,‘900px’。
今天的分享結束了,暖寶自己畫了個卡通暖寶獻給大家
記得關注暖夕H2,大家注意保暖哦~~
*請認真填寫需求信息,我們會在24小時內與您取得聯系。