Asked Aug 8th, 8:02 a.m. 140 0 1
  • 140 0 1
0

Hỏi về cách sử dụng router lồng trong VuJs để truyền params từ trang này qua trang khác

Share
  • 140 0 1

Em đang có 1 router lồng như thế này:

  {
    path: '/recruit',
    name: 'Recruit',
    component: () => import(/* webpackChunkName: "Recruit" */ '../views/Recruit/index.vue'),
    children: [
      {
          path: "/recruit/:locale",
          component: () => import(/* webpackChunkName: "Recruit" */ '../views/Recruit/index.vue'),
      },
  ],
  },

Khi em click và đổi locale params của trang web thành: localhost:8080/en và em muốn khi click chuyển qua 1 trang khác bất kỳ thì nó vẫn giữ được locale params ví dụ qua trang recruit thì nó có đường dẫn là localhost:8080/recruit/en, đây là router link mà em đang sử dụng:

 <router-link
                class="nav-link rttr"
                :to="{ name: 'Recruit'}"
              >
                Tuyển dụng
              </router-link>

Nếu em tách router trên thành 2 router riêng thì chỉ có thằng recruit/:locale là hoạt động còn khi bên trang chủ chưa có local params thì nó vẫn dẫn đến trang /recruit nhưng giao diện vẫn nằm ở trang chủ, và ngược lại khi em dùng router lồng thì không thể lấy được router params từ trang chủ qua các trang khác. Cảm ơn mọi người đã bỏ chút thời gian đọc bài, mong nhận được sự giúp đỡ từ mọi người.

Code 2 component ở trang chủ là header + Fearute:

Header.vue:

<template>
  <div id="header-top" class="header-top sticky-top">
    <nav class="navbar navbar-expand-lg navbar-light">
      <a class="navbar-brand" href="/">
        <img src="../assets/home/logo.svg" alt="" id="logo"
      /></a>
      <button
        class="navbar-toggler"
        id="btn-navbar"
        type="button"
        data-toggle="collapse"
        data-target="#navbarNavDropdown"
        aria-controls="navbarNavDropdown"
        aria-expanded="false"
        aria-label="Toggle navigation"
      >
        <span class=""
          ><img
            src="../assets/home/align-right-svgrepo-com.svg"
            alt="GoStream Tech"
        /></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarNavDropdown">
        <ul class="navbar-nav" id="menu">
          <div class="list-nav-item">
            <li>
              <a
                @click="active = null"
                :class="{ active: active === null }"
                href="/"
                class="nav-link"
                >{{ localised("home") }}</a
              >
            </li>
            <li class="nav-item">
              <a
                @click="active = 'about'"
                :class="{ active: active === 'about' }"
                href="#about"
                class="nav-link"
                >{{ localised("about") }}</a
              >
            </li>
            <li class="nav-item">
              <a
                @click="active = 'newspaper'"
                :class="{ active: active === 'newspaper' }"
                href="#Newspaper"
                class="nav-link"
                >{{ localised("newspaper") }}</a
              >
            </li>
            <li class="nav-item">
              <!-- <a class="nav-link rttr"  @click="recruitClick">
                
              {{ localised("recruit") }}</a> -->
              <router-link
                class="nav-link rttr"
                :to="{ name: 'Recruit'}"
              >
                {{ localised("recruit") }}
              </router-link>
            </li>
            <li class="nav-item">
              <a
                @click="active = 'contact'"
                :class="{ active: active === 'contact' }"
                href="#contact"
                class="nav-link"
                >{{ localised("contact") }}</a
              >
            </li>
          </div>

          <li class="nav-item dropdown" id="language">
            <a
              class="nav-link"
              href="#"
              id="navbarDropdownMenuLink"
              role="button"
              data-toggle="dropdown"
              aria-expanded="false"
            >
              <img :src="flag" alt="" />
              <b>{{ nation }}</b>
            </a>
            <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
              <a class="language-Viet row" href="/vi">
                <div class="language-popup">
                  <img src="../assets/home/image 18.svg" @click="changeLanguage(1)" alt="" />
                  <b value="vi" >Tiếng Việt</b>
                </div>
              </a>
              <a class="language-English row" href="/en">
                <div class="language-popup">
                  <img src="../assets/home/image 19.svg" alt="" />
                  <b value="en">English</b>
                </div>
              </a>
            </div>
          </li>
        </ul>
      </div>
    </nav>
  </div>
</template>

<script>
import "../assets/style.css";
import "../assets/boostrap.css";
import "../views/Home/NewsPaper.vue";
export default {
  data() {
    return {
      active: null,
      activeLocale: "vi",
      dosomething:'',
      menu: {
        en: {
          home: "Home",
          about: "About",
          newspaper: "Newspaper",
          recruit: "Recruit",
          contact: "Contact",
        },
        vi: {
          home: "Trang chủ",
          about: "Về chúng tôi",
          newspaper: "Tin tức",
          recruit: "Tuyển dụng",
          contact: "Liên hệ",
        },
      },
    };
  },
  mounted() {
    if (this.$route.params.locale == null) {
      this.activeLocale = "vi";
    } else {
      this.activeLocale = this.$route.params.locale;
    }

    //test case label multiple language
    // var localeGS = this.$route.params.locale
    // switch(localeGS){
    //   case null:{
    //       return this.dosomething = 'VN'
    //   }
    //   case 'vi':{
    //     return this.dosomething = 'VN'
    //   }
    //   case 'en':{
    //     return this.dosomething = 'EN'
    //   }

    // }
  },
  methods: {
 changeLanguage(language) {
    // set ngôn ngữ với key là currentLanguage
    localStorage.currentLanguage = language;
  },
    localised(key) {
      return this.menu[this.activeLocale][key];
    },
  },
  computed: {
    locale() {
      return this.$route.params.locale;
    },

nation() {
  if (this.$route.params.locale === 'en') {
    return 'EN'
  }
  else{
    return 'VN'
  }
},
    flag() {
      if (this.$route.params.locale == "vi") {
        return require("../assets/home/image 18.svg");
      }
       if (this.$route.params.locale == null) {
        return require("../assets/home/image 18.svg");
    }
    if(this.$route.params.locale == 'en'){
       return require("../assets/home/image 19.svg");
    }
    },
  },
};
</script>

<style>
</style>

Feature.vue:

<template>
  <div  class="container feature">
    <div class="logo-feature">
      <div class="feature-detail">
        <img class="feature-avt" src="../assets/home/logo.svg" alt="" />
        <div class="btn-feature">
          <a href="">
            <img src="../assets/home/circle.svg" alt="" />
            <img class="go-feature" src="../assets/home/go-r.svg" alt=""
          /></a>
        </div>
      </div>
      <div class="feature-detail">
        <img class="feature-avt" src="../assets/home/gostudio.png" alt="" />

        <div class="btn-feature">
          <a href="">
            <img src="../assets/home/circle.svg" alt="" />
            <img class="go-feature" src="../assets/home/go-r.svg" alt=""
          /></a>
        </div>
      </div>
      <div class="feature-detail">
        <img class="feature-avt" src="../assets/home/image 32x.png" alt="" />
        <div class="btn-feature">
          <a href="">
            <img src="../assets/home/circle.svg" alt="" />
            <img class="go-feature" src="../assets/home/go-r.svg" alt=""
          /></a>
        </div>
      </div>
      <div class="feature-detail">
        <img class="feature-avt" src="../assets/home/image 112x.png" alt="" />
        <div class="btn-feature">
          <a href="">
            <img src="../assets/home/circle.svg" alt="" />
            <img class="go-feature" src="../assets/home/go-r.svg" alt=""
          /></a>
        </div>
      </div>
    </div>
    <div id="about" v-for="(item, index) in abouts" :key="index">
      <div class="intro">
        <img src="../assets/home/building-1.png" alt="" />
        <h5>{{ item.firsTitle }}</h5>
        <h2>{{ item.titleProduct }}</h2>
        <h3>{{ item.nameProduct }}</h3>
        <h6>{{ item.firsContent }}</h6>
      </div>
      <div class="livestream">
        <div class="livestream-img">
          <img :src="`https://cms.gstech.space${item.imageAbout.url}`" alt="" />
        </div>
        <div class="livestream-intro">
          <h5>{{ item.titleAbout }}</h5>
          <h6>{{ item.descriptionAbout }}</h6>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      abouts: [],
    };
  },
  created() {},
  async mounted() {
    if (this.$route.params.locale == null) {
      await axios
        .get(`https://cms.gstech.space/abouts`)
        .then((response) => {
          this.abouts = response.data;
          console.log("ABoout", response.data);
        })
        .catch((e) => {
          this.errors.push(e);
        });
    } else {
      await axios
        .get(`https://cms.gstech.space/abouts?_locale=${this.locale}`)
        .then((response) => {
          this.abouts = response.data;
        })
        .catch((e) => {
          this.errors.push(e);
        });
    }
  },
  computed: {
    locale() {
      return this.$route.params.locale;
    },
  },
};
</script>

<style>
body,
html {
  scroll-behavior: smooth;
}
.btn-feature {
  width: 35px;
  height: 35px;
  position: relative;
  top: 55px;
  right: 112px;
  align-items: center;
  text-align: center;
  justify-content: center;
  display: flex;
}
@keyframes example {
  0% {
    transform: translateX(-60%);
  }
  100% {
    transform: translateX(30%);
  }
}

.go-feature {
  position: relative !important;
  /* margin: 0 auto; */
  /* justify-content: center; */
  /* right: -33px; */
  top: 10px;
  left: 16px !important;
}
.btn-feature:hover .go-feature {
  animation-name: example;
  animation-duration: 1.5s;
  animation-iteration-count: infinite;
  margin-top: 10px;
  /* left: 0;
    top: 0px;
    margin: 0 auto; */
}
</style>

1 ANSWERS


Answered Aug 8th, 8:58 a.m.
Accepted
0

Theo em hiểu thì ý bác là muốn khi đang ở trang chủ người dùng để ngôn ngữ là tiếng anh 'en' thì khi chuyển trang khác bác vẫn muốn để tiếng anh đúng không nhỉ? Nếu bác muốn làm thế thì bác có thể tạo một biến vào localStorage để lưu ngôn ngữ hiện tại ví dụ như: currenLanguage: 'en'. Rồi những trang khác bác hòan toàn có thể lấy từ localStorage ra ngôn ngữ hiện tại của người dùng.

Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 8th, 9:10 a.m.

Thằng localStorage thì mình tạo ở đâu bác, bác có thể cho em 1 xí minh hoạ cụ thể được không ạ? e cảm ơn bác nhiều lắm ^^

0
| Reply
Share
Aug 8th, 9:28 a.m.

@binchanhkun99 Ví dụ như phần đổi ngôn ngữ bác dùng hàm changeLanguage thì khi sử dụng localStorage sẽ như sau

methods: {
  changeLanguage(language) {
    // set ngôn ngữ với key là currentLanguage
    localStorage.currentLanguage = language;
  }
  getLanguage() {
    // lấy ngôn ngữ hiện tại từ localStorage ra
    console.log(localStorage.currentLanguage);
  }
}

Để hiểu hơn về localStorage bác có thể xem ở đây và ở đây

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 8th, 9:35 a.m.

@dangcq17 em đọc r nhưng vẫn chưa hiểu ý bác lắm ạ, bh em đổi ngôn ngữ em đang dùng thẻ a link đến 1 đường dẫn rồi thêm cái params vào sau bởi vì trang của em yêu cầu lấy ngôn ngữ từ api nên phải tải lại trang nên e ko methods

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 8th, 9:38 a.m.

@dangcq17 Với bh ý bác là e tạo default thằng currentLang là 'vi' hc 'en' rồi khi chuyển trang lấy cái thằng ngôn ngữ mình vừa đổi mà thằng localStorage bắt đc đúng k bác nhỉ?

0
| Reply
Share
Aug 8th, 9:46 a.m.

@binchanhkun99 em thấy nếu mục đích của bác là chỉ để làm đa ngôn ngữ cho trang web thì bác không cần thiết phải hiện ngôn ngữ hiện tại trên URL kiểu như recruit/en. Vì trên menu của bác cũng có icon thể hiện là ngôn ngữ hiện tại của người dùng rồi nên bác sửa lại logic một chút là thay vì mình lấy currentLanguage trên URL mà mình sẽ dùng luôn thằng localStorage để quả lý cho việc đa ngôn ngữ cho trang mỗi lần người dùng đổi ngôn ngữ thì bác set lại vào trong localStorage thôi và khi muốn lấy ngôn ngữ hiện tại để hiển thị content thì bác cũng lấy luôn trong localStorage ra. Bác nhớ để ý handle phần khi trong localStorage chưa có ngôn ngữ hiện tại lúc lấy ra nó sẽ không có.

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 8th, 9:54 a.m.

@dangcq17 tức là bh thay vì đang sử dụng this.$route.params.locale thì mình chủ động set luôn cái lang ấy vào localStorage rồi dùng phương thức changeLang mỗi khi click vào dropdown thì lấy cái giá trị trên truyền vào cái key "language" đúng không bác nhỉ?

0
| Reply
Share
Aug 8th, 9:56 a.m.

@binchanhkun99 đúng rồi bác

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 8th, 9:59 a.m.

@dangcq17 Nhưng nếu như vậy thì khi em chuyển qua trang khác nó có giữ cái trạng thái cái curentLanguage trong localStorage ko vậy bác nhỉ?

0
| Reply
Share
Aug 8th, 10:01 a.m.

@binchanhkun99 vẫn giữ bác nhé. Ví du luôn cho bác trang https://viblo.asia/followings đây. Bác thử kéo xuống dưới cùng chỉnh phần language sang ngôn ngữ nào cũng được rồi bác bật F12 -> Application -> Local Storage -> https://viblo.asia thì bác sẽ thấy một key là preferred_locale

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 8th, 10:11 a.m.

@dangcq17 nhưng em hỏi ngu thêm xíu với bác ơi, ví dụ như ở trang chủ em có các component riêng thì e có cần props hay thằng localStorage.currentLanguage qua không ạ? hay là phải làm như thế nào để các component con nhận đc cái localStorage.currentLanguage từ component Header v ạ? Với bác cho em xin i4 em gửi bác ly cf với chứ hỏi nhiều e cũng ngại lắm ahjhj ^^

+1
| Reply
Share
Aug 8th, 10:14 a.m.

@binchanhkun99 không có gì đâu bác 😄. Ở bất cứ component nào bác chỉ cần lấy từ localStorage như ở bên trên code em đưa ban đầu cho bác là được nhé. Không chỉ ở method mà trong computed bác cũng có thể dùng được localStorage

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 8th, 10:16 a.m.

@dangcq17 Vâng bác ơi, cơ mà em phải đổi ngôn ngữ theo api đc gọi(vì các nội dung của trang cả tiếng anh lẫn tiếng Việt đều lưu trong database) nên chắc ko load trang thì k đc rồi á bác :_) hjx

0
| Reply
Share
Aug 8th, 10:19 a.m.

@binchanhkun99 bac cho em xin full code của 1 component nào đó xem để em xem bác code như nào rồi em chỉ cho. Mà backend (techstack) bác đang dùng gì nhỉ.

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 8th, 10:25 a.m.

@dangcq17 backend thì react với nodejs bác ạ, project này sử dụng Strapi để quản lý cms với làm việc với BE luôn á bác, nó hỗ trợ 1 thằng gọi là strapi-i18 tức là nó cho phép mình tạo 1 bảng có các option đa ngôn ngữ để mình thêm data vào và quản lý đa ngôn ngữ trong bảng ấy luôn, Vâng bác code thì để em update lên bài luôn nha bác

0
| Reply
Share
Aug 8th, 10:29 a.m.

@binchanhkun99 theo em hiểu thì api đó sẽ iểu là /api/posts?locale=en thì lúc bác change language thì chỉ cần gọi lại api với ngôn ngữ tương ứng là được mà nhỉ. Sau khi call bác gán lại data cho component là content nó sẽ đổi thôi.

0
| Reply
Share
Aug 8th, 10:30 a.m.

@binchanhkun99 em vừa thấy code của bác, em thấy code của bác đang lặp phần call api thì bác nên tách call api ra thành 1 async method xong sau đó trong mounted bác chỉ cần gọi method đó thôi ✌️

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 8th, 10:34 a.m.

@dangcq17 vâng cái đó chắc e sẽ optimal lại sau nhưng mà em hỏi xí là nếu dùng thằng Storage thì thuật toán em phải đổi phải k bác nhỉ? trc e để lá cờ với cái text phía sau trong comuted load lại trang là nó đổi giờ ntn thì e phải đặt nó vào watch hay sao bác nhỉ? sao k cần load lại trang mà lá cờ nó vẫn đổi sau khi click ấy bác 😅

0
| Reply
Share
Aug 8th, 10:42 a.m.

@binchanhkun99

<template>
    <div id="header-top" class="header-top sticky-top">
        <nav class="navbar navbar-expand-lg navbar-light">
            <a class="navbar-brand" href="/">
                <img src="../assets/home/logo.svg" alt="" id="logo" /></a>
            <button class="navbar-toggler" id="btn-navbar" type="button" data-toggle="collapse"
                data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false"
                aria-label="Toggle navigation">
                <span class=""><img src="../assets/home/align-right-svgrepo-com.svg" alt="GoStream Tech" /></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNavDropdown">
                <ul class="navbar-nav" id="menu">
                    <div class="list-nav-item">
                        <li>
                            <a @click="active = null" :class="{ active: active === null }" href="/" class="nav-link">{{
                                    localised("home")
                            }}</a>
                        </li>
                        <li class="nav-item">
                            <a @click="active = 'about'" :class="{ active: active === 'about' }" href="#about"
                                class="nav-link">{{ localised("about") }}</a>
                        </li>
                        <li class="nav-item">
                            <a @click="active = 'newspaper'" :class="{ active: active === 'newspaper' }"
                                href="#Newspaper" class="nav-link">{{ localised("newspaper") }}</a>
                        </li>
                        <li class="nav-item">
                            <!-- <a class="nav-link rttr"  @click="recruitClick">
                
              {{ localised("recruit") }}</a> -->
                            <router-link class="nav-link rttr" :to="{ name: 'Recruit' }">
                                {{ localised("recruit") }}
                            </router-link>
                        </li>
                        <li class="nav-item">
                            <a @click="active = 'contact'" :class="{ active: active === 'contact' }" href="#contact"
                                class="nav-link">{{ localised("contact") }}</a>
                        </li>
                    </div>

                    <li class="nav-item dropdown" id="language">
                        <a class="nav-link" href="#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown"
                            aria-expanded="false">
                            <img :src="flag" alt="" />
                            <b>{{ nation }}</b>
                        </a>
                        <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
                            <a class="language-Viet row" href="/vi">
                                <div class="language-popup">
                                    <img src="../assets/home/image 18.svg" @click="changeLanguage(1)" alt="" />
                                    <b value="vi">Tiếng Việt</b>
                                </div>
                            </a>
                            <a class="language-English row" href="/en">
                                <div class="language-popup">
                                    <img src="../assets/home/image 19.svg" alt="" />
                                    <b value="en">English</b>
                                </div>
                            </a>
                        </div>
                    </li>
                </ul>
            </div>
        </nav>
    </div>
</template>

<script>
import "../assets/style.css";
import "../assets/boostrap.css";
import "../views/Home/NewsPaper.vue";
export default {
    data() {
        return {
            active: null,
            activeLocale: "vi",
            dosomething: '',
            menu: {
                en: {
                    home: "Home",
                    about: "About",
                    newspaper: "Newspaper",
                    recruit: "Recruit",
                    contact: "Contact",
                },
                vi: {
                    home: "Trang chủ",
                    about: "Về chúng tôi",
                    newspaper: "Tin tức",
                    recruit: "Tuyển dụng",
                    contact: "Liên hệ",
                },
            },
        };
    },

    mounted() {
        if (localStorage.currentLanguage) {
            this.activeLocale = localStorage.currentLanguage;
        }
    },

    methods: {
        changeLanguage(language) {
            // set ngôn ngữ với key là currentLanguage
            localStorage.currentLanguage = language;
            this.activeLocale = language;
        },

        localised(key) {
            return this.menu[this.activeLocale][key];
        },
    },
    computed: {
        nation() {
            if (this.activeLocale === 'en') {
                return 'EN'
            }
            
            return 'VN';
        },

        flag() {
            if (this.activeLocale === 'en') {
                return require("../assets/home/image 19.svg");
            }

            return require("../assets/home/image 18.svg");
        },
    },
};
</script>

bác dùng thử đoạn này xem chạy chưa nhé

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 9th, 1:07 a.m.

@dangcq17 ui ngon lành bác ạ, nhưng mà với những component khác call api thì sao bác nhỉ? khi em đổi trạng thái cái dropdown thì làm sao nó load lại api ở các component khác v ạ?

0
| Reply
Share
Aug 9th, 2:16 a.m.

@binchanhkun99 trong hàm change language thì bác append thêm query như dashboard?lang=en sau đó trong các component bác watch thằng query này rồi gọi hàm call api thôi

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 9th, 2:19 a.m.

@dangcq17 Cái này e chưa làm bao giờ bác ạ có thể demo giúp e dc ko ạ? mà bác cho em xin i4 với em gửi bác cốc cf vì những đóng góp của bác cho e và cộng đồng ^^

0
| Reply
Share
Avatar Phạm Duy Vũ @binchanhkun99
Aug 9th, 9:57 a.m.

😢@dangcq17 image.png

sếp thì bảo lm ntn nhưng ko biết cache trong Vue sử dụng ntn bác nhỉ😥

0
| Reply
Share
Viblo
Let's register a Viblo Account to get more interesting posts.