整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Vue實戰-Router動態傳遞參數實現新聞詳情頁

          Vue實戰-Router動態傳遞參數實現新聞詳情頁

          文(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 中簡單的話題,但是感覺卻比較稀罕,因為這個技能點,有的小伙伴們可能沒聽過!

          1.緣起

          說到 Web 請求參數傳遞,大家能想到哪些參數傳遞方式?

          參數可以放在地址欄中,不過地址欄參數的長度有限制,并且在有的場景下我們可能不希望參數暴漏在地址欄中。參數可以放在請求體中,這個沒啥好說的。

          小伙伴們試想這樣一個場景:

          在一個電商項目中,有一個提交訂單的請求,這個請求是一個 POST 請求,請求參數都在請求體中。當用戶提交成功后,為了防止用戶刷新瀏覽器頁面造成訂單請求重復提交,我們一般會將用戶重定向到一個顯示訂單的頁面,這樣即使用戶刷新頁面,也不會造成訂單請求重復提交。

          大概的代碼就像下面這樣:

          @Controller
          public class OrderController {
              @PostMapping("/order")
              public String order(OrderInfo orderInfo) {
                  //其他處理邏輯
                  return "redirect:/orderlist";
              }
          }
          

          這段代碼我相信大家都懂吧!如果不懂可以看看松哥錄制的免費的 SpringMVC 入門教程(硬核!松哥又整了一套免費視頻,搞起!)。

          但是這里有一個問題:如果我想傳遞參數怎么辦?

          如果是服務器端跳轉,我們可以將參數放在 request 對象中,跳轉完成后還能拿到參數,但是如果是客戶端跳轉我們就只能將參數放在地址欄中了,像上面這個方法的返回值我們可以寫成:return "redirect:/orderlist?xxx=xxx";,這種傳參方式有兩個缺陷:

          • 地址欄的長度是有限的,也就意味著能夠放在地址欄中的參數是有限的。
          • 不想將一些特殊的參數放在地址欄中。

          那該怎么辦?還有辦法傳遞參數嗎?

          有!這就是今天松哥要和大家介紹的 flashMap,專門用來解決重定向時參數的傳遞問題。

          2.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 中有兩種添加參數的方式:

          • addFlashAttribute:將參數放到 flashMap 中。
          • addAttribute:將參數放到 URL 地址中。

          經過前面的講解,現在小伙伴們應該大致明白了 flashMap 的作用了,就是在你進行重定向的時候,不通過地址欄傳遞參數。

          很多小伙伴可能會有疑問,重定向其實就是瀏覽器發起了一個新的請求,這新的請求怎么就獲取到上一個請求保存的參數呢?這我們就要來看看 SpringMVC 的源碼了。

          3.源碼分析

          首先這里涉及到一個關鍵類叫做 FlashMapManager,如下:

          public interface FlashMapManager {
           @Nullable
           FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);
           void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
          }
          

          兩個方法含義一眼就能看出來:

          • retrieveAndUpdate:這個方法用來恢復參數,并將恢復過的的參數和超時的參數從保存介質中刪除。
          • saveOutputFlashMap:將參數保存保存起來。

          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;
          }
          
          • 首先調用 retrieveFlashMaps 方法從 session 中獲取到所有的 FlashMap。
          • 調用 getExpiredFlashMaps 方法獲取所有過期的 FlashMap,FlashMap 默認的過期時間是 180s。
          • 獲取和當前請求匹配的 getMatchingFlashMap,具體的匹配邏輯就兩點:重定向地址要和當前請求地址相同;預設參數要相同。一般來說我們不需要配置預設參數,所以這一條可以忽略。如果想要設置,則首先給 flashMap 設置,像這樣:flashMap.addTargetRequestParam("aa", "bb");,然后在重定向的地址欄也加上這個參數:return "redirect:/orderlist?aa=bb"; 即可。
          • 將獲取到的匹配的 FlashMap 對象放入 mapsToRemove 集合中(這個匹配到的 FlashMap 即將失效,放入集合中一會被清空)。
          • 將 allFlashMaps 集合中的所有 mapsToRemove 數據清空,同時調用 updateFlashMaps 方法更新 session 中的 FlashMap。
          • 最終將匹配到的 flashMap 返回。

          這就是整個獲取 flashMap 的方法,整體來看還是非常 easy 的,并沒有什么難點。

          4.小結

          好啦,今天就和小伙伴們分享了一下 SpringMVC 中的 flashMap,不知道大家有沒有在工作中用到這個東西?如果剛好碰到松哥前面所說的需求,用 FlashMap 真的還是蠻方便的。如果需要下載本文案例,小伙伴們可以在公眾號【江南一點雨】后臺回復 20210302,好啦,今天就和大家聊這么多~

          天呢,暖寶給大家帶來javascript的歷險函數傳參,如果覺得好的話,動動手指關注暖夕H2,文末有彩蛋哦~~

          javascript的參數:

          上圖為示例代碼:

          1.“num“,“value”為參數

          2.在button按鈕中改變函數的值,只需要調用change()這個函數的的參數的值就行了,上圖示例為改變一個對象的寬度。

          什么叫作對象?

          比如上圖first就是一個對象,它的style為它的屬性。

          什么就作字面量?

          就是你在js里能夠看到的帶引號的值。

          比如上文的‘width’,‘900px’。

          今天的分享結束了,暖寶自己畫了個卡通暖寶獻給大家

          記得關注暖夕H2,大家注意保暖哦~~


          主站蜘蛛池模板: 日本精品一区二区三本中文| 三上悠亚一区二区观看| 中文字幕无线码一区| 国产一区二区三区夜色| 美女福利视频一区| 日本免费一区二区三区四区五六区| 亚洲一区中文字幕在线观看| 亚洲愉拍一区二区三区| 国产人妖视频一区在线观看| 久久精品中文字幕一区| 国产免费一区二区视频| 亚洲av无码一区二区三区人妖| 日韩动漫av在线播放一区| 精品视频一区二区三区在线观看 | 精品国产日韩亚洲一区| 中文字幕在线观看一区二区 | 久久国产高清一区二区三区 | 一区二区三区精品高清视频免费在线播放 | 亚洲性日韩精品国产一区二区 | 一区二区在线电影| 亚洲国产欧美一区二区三区| 精品福利一区二区三区| 3d动漫精品成人一区二区三| 波多野结衣一区在线观看| 91精品国产一区二区三区左线| 激情综合丝袜美女一区二区 | 日本片免费观看一区二区| 一区二区三区观看| 久久久国产精品无码一区二区三区| 国产一区二区女内射| 无码人妻精品一区二区三区99不卡| 蜜臀AV免费一区二区三区| 久久婷婷色综合一区二区| 在线日韩麻豆一区| 亚洲av色香蕉一区二区三区蜜桃 | 国产综合无码一区二区辣椒| 国产精品亚洲专区一区| 午夜福利无码一区二区| 乱色精品无码一区二区国产盗| 亚洲高清成人一区二区三区| 在线欧美精品一区二区三区|