VueJS 中的模型 URL 参数

Model URL parameter in VueJS

从 继续,我只是想操作一个范围输入元素并使用该值更新 URL。

// https://github.com/vuejs/vue-router/blob/dev/examples/route-props/Hello.vue
var Hello = Vue.component('Hello', {
  template: `
  <div>
  <h2 class="hello">Hello {{agility}} {{ $attrs }}</h2>
  <input min=0 max=100 v-model="agility" type="range">
  </div>
  `,
  props: {
    agility: {
      type: Number,
      default: 25
    }
  }
});

const router = new VueRouter({
  // mode: 'history',
  routes: [
    { path: '*', component: Hello, props: true },
    { path: '/:agility', component: Hello, props: true },
  ]
})

new Vue({
  router,
  template: `
    <div id="app">
      <router-view></router-view>
    </div>
  `
}).$mount('#app')
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app"></div>

当没有提供任何值时,我希望将默认值 25 附加到 URL,例如https://dabase.com/tips/web/2021/Minimal-VueJS-route-bind/#25

如果有没有 vue-router 的更简单的方法,我洗耳恭听!

不用vue-router我解决了!

这里我们使用从 URL 散列部分得到的数据来设置数据:

  created: function() {
    var hash = window.location.hash.substr(1)
    if (hash) {
        this.agility = hash
        }
  },

当数据发生变化时,更新URL散列部分

   watch: {
    agility: function (newValue) {
      window.location.hash = newValue
    }
  },

虽然该解决方案有效,但存在两个问题:

  • Hello 组件改变了它自己的 agility 属性。这不应该发生(Vue 在控制台中生成警告),而是应该发出一个事件,以便上游更改 属性。这样,值总是只存储在一个地方,修改那个地方的值将在其他地方修改它。
  • 如果 url 的哈希值发生变化,由于用户手动输入新的 url 或单击 link,输入中的值将不会更新

为了解决第一个问题,我们不会在 agility 属性 上使用 v-model,因为我们不想改变它。我们需要直接监听输入的事件:

<input min=0 max=100 :value="agility" type="range" @input="updateAgility">
{
   ...,
   methods: {
     updateAgility(event /*: InputEvent */) {
       this.$router.push({...this.$route, hash: "#" + event.target.value});
     }
   }
}

这将在输入更改值时直接更改 url。第二个问题是当 url 改变时如何更新 prop agility.

created 中这样做是不够的,因为如果页面保持不变但哈希发生变化,则不会重新创建组件。

所以我们回到原来的解决方案,直接从路由器设置prop:

{ 
  path: "*", 
  component: Hello, 
  props: route => route.hash.length > 1 ? 
     { agility: Number(route.hash.slice(1))} :
     {}
}

现在,无论您是从 URL 还是输入更新值,URL 和输入值始终保持同步。关于改变道具的警告消失了。

// https://github.com/vuejs/vue-router/blob/dev/examples/route-props/Hello.vue
var Hello = Vue.component('Hello', {
  template: `
  <div>
  <h2 class="hello">Hello {{agility}}, Current route's hash: {{ $route.hash}}</h2>
  <input min=0 max=100 :value="agility" @input=updateAgility type="range">
  <br>
  <router-link to="#1">Hash 1 link</router-link>   <router-link to="#15">Hash 15 link</router-link>
  </div>
  `,
  props: {
    agility: {
      type: Number,
      default: 25
    }
  },
  methods: {
    updateAgility(event/*: InputEvent */) {
      this.$router.push({...this.$route, hash: "#" + event.target.value});
    }
  }

});

const router = new VueRouter({
  // mode: 'history',
  routes: [
    { path: '*', component: Hello, props: route => route.hash.length > 1 ? { agility: Number(route.hash.slice(1))} : {}},
  ]
})

new Vue({
  router,
  template: `
    <div id="app">
      <router-view></router-view>
    </div>
  `
}).$mount('#app')
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app"></div>

仅供参考:也可以通过在 '$route.hash' 上创建观察器来监听组件本身的 url 变化,但这不是推荐的方式。

不用路由器也可以优雅高效的完成。使用更改或输入事件来更新哈希。

new Vue({
  el: "#app",
  data: {
    agility: 25,
    hash: 0
  },
  methods: {
    addHash() {
      window.location.hash = this.agility;
      this.hash = this.agility;
    }
  },
  created: () => {
    const hash = window.location.hash.substr(1)
    if (hash) {
      this.agility = hash
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>

<div id="app">
  <h2 class="hello">Hello {{agility}}</h2>
  <input min=0 max=100 v-model="agility" @change="addHash" type="range">
  <h4>testing hash = {{hash}}</h4>
</div>

Change 事件在用户停止滚动或离开输入范围缩略图时触发。如果您想在移动拇指时看到变化,请使用输入事件。

为此创建一个可写的 cmoputed 属性。我认为这还不错,因为当您需要更新路线时,只需分配 this.agility = newAgility 即可,一切正常。要设置默认值 25,可以使用 created 挂钩。

但请记住,如此频繁地改变您的路线可能会导致性能问题。考虑在计算的 属性 上限制 set 函数(您可以使用 lodash.throttle 或实现您自己的)或将路由参数替换为散列参数。

// https://github.com/vuejs/vue-router/blob/dev/examples/route-props/Hello.vue
var Hello = Vue.component('Hello', {
  template: `
  <div>
  <h2 class="hello">Hello {{agility}}</h2>
  <input min=0 max=100 v-model="agility" type="range">
  </div>
  `,
  created() {
    if (typeof this.agility === 'undefined') {
      this.agility = 25;
    }
  },
  computed: {
    agility: {
      get() {
        return this.$route.params.agility;
        // Or with hash parameter
        // return this.$route.hash;
      },
      set(agility) {
        this.$router.replace(`/${agility}`);
        // Or with hash parameter
        // this.$router.replace({ hash: String(agility) });
      },
    },
  },
});

const router = new VueRouter({
  // mode: 'history',
  routes: [
    { path: '*', component: Hello },
    { path: '/:agility', component: Hello },
  ]
})

new Vue({
  router,
  template: `
    <div id="app">
      <router-view></router-view>
    </div>
  `
}).$mount('#app')
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app"></div>