Vue Router错误地将params作为整数而不是字符串

时间:2018-04-19 15:08:54

标签: vue.js vue-router

当我使用浏览器字段输入URL时,参数被转换为字符串,而不是整数,例如/user/1返回{id: "1"}。但是,当使用this.$route.push({})时,params正确地转换为整数{id: 1}

这种行为是否有意?如果没有,我该如何解决?

6 个答案:

答案 0 :(得分:5)

你必须自己处理任何params值。在route对象中定义一个props函数。这是一个例子:

{
  path: '/user/:userId',
  component: UserProfile,
  props: (route) => {
    const userId = Number.parseInt(route.params.userId, 10)
    if (Number.isNaN(userId)) {
      return 0
    }
    return { userId }
  }
}

link vue路由器文档,这是在功能模式下

答案 1 :(得分:1)

我可能聚会晚了,但这是我的看法。我编写了一个函数,该函数返回的函数会将路由参数值转换为具有给定类型的同名道具。

function paramsToPropsCaster(mapping) {
  return function(route) {
    let nameType = Object.entries(mapping);  // [[param1, Number], [param2, String]]
    let nameRouteParam = nameType.map(([name, fn]) => [name, fn(route.params[name])]);  // [[param1, 1], [param2, "hello"]]
    let props = Object.fromEntries(nameRouteParam);  // {param1: 1, param2: "hello"}
    return props;
  }
}

然后,在您的路线定义中:

{
      path: '/projects/:param1/editor/:param2', 
      component: ProjectEditor,
      name: 'project-editor',
      props: paramsToPropsCaster({'param1': Number, 'param2': String}),
}

这仅是您可以用来解决此处提出的问题的提示,请不要使用此逐字记录!

答案 2 :(得分:0)

Vue Router 似乎没有为此提供快捷方式,所以我想出了自己的快捷方式。下面的 castParams 函数生成一个内置指定类型转换的 props 函数。我为整数和布尔值添加了转换,但您可以轻松地将其扩展为您想要转换的任何其他类型。

// casts should be an object where the keys are params that might appear in the route, and the values specify how to cast the parameters
const castParams = (casts) => {
    return (route) => {
        const props = {};
        for (var key in route.params) {
            const rawValue = route.params[key];
            const cast = casts[key];
            if (rawValue == null) {
                // Don't attempt to cast null or undefined values
                props[key] = rawValue;
            } else if (cast == null) {
                // No cast specified for this parameter
                props[key] = rawValue;
            } else if (cast == 'integer') {
                // Try to cast this parameter as an integer
                const castValue = Number.parseInt(rawValue, 10);
                props[key] = isNaN(castValue) ? rawValue : castValue;
            } else if (cast == 'boolean') {
                // Try to cast this parameter as a boolean
                if (rawValue === 'true' || rawValue === '1') {
                    props[key] = true;
                } else if (rawValue === 'false' || rawValue === '0') {
                    props[key] = false;
                } else {
                    props[key] = rawValue;
                }
            } else if (typeof(cast) == 'function') {
                // Use the supplied function to cast this param
                props[key] = cast(rawValue);
            } else {
                console.log("Unexpected route param cast", cast);
                props[key] = rawValue;
            }
        }
        return props;
    };
};

然后你可以在你的路由定义中使用它,例如:

{
    path: '/contact/:contactId',
    component: 'contact-details-page',
    props: castParams({contactId: 'integer'}),
},

答案 3 :(得分:0)

我更喜欢 Rodener Dajes 的回答,并在组件内而不是在路由定义中处理类型转换和验证:

props: {
        id: {
            type: [Number, String],
            default: 0
        },
    },

原因是它能让我定义更简单易读的路线:

{
path: '/job/:id',
name: 'Job',
component: InvoiceJobDetail,
props: true
}

答案 4 :(得分:0)

其中许多解决方案对我来说似乎没有必要复杂。

这是我在我的项目中所做的 - 请注意,以 ID 结尾的路由参数或参数 id 本身会自动转换为 Number,因此在我的情况下,我只需要在我几乎所有的路线中都设置了 props: typedProps(),

/**
 * Casts props into proper data types.
 * Props ending in 'ID' and the prop 'id' are cast to Number automatically.
 * To cast other props or override the defaults, pass a mapping like this:
 * @example
 * // Truthy values like 'true', 'yes', 'on' and '1' are converted to Boolean(true)
 * {
 *  path: '/:isNice/:age/:hatSize',
 *  name: 'foo route',
 *  props: typedProps({ isNice: Boolean, age: Number, hatSize: Number}),
 * },
 * @param {Object} mapping
 * @returns
 */
const typedProps = (mapping) => {
  if (!mapping) {
    mapping = {}
  }
  
  return (route) => {
    let props = {}
    for (let [prop, value] of Object.entries(route.params)) {
      if (prop in mapping) {
        if (mapping[prop] === Boolean) {
          value = ['true', '1', 'yes', 'on'].includes(value.toLowerCase())
        } else {
          value = mapping[prop](value)
        }
      } else if (prop === 'id' || prop.endsWith('ID')) {
        value = Number(value)
      }
      
      props[prop] = value
    }

    return props
  }
}

如果类型强制失败,这可能会使用一些错误处理,但我将把它留给读者作为练习:)

答案 5 :(得分:-1)

您可以在props中使用数组来支持两种类型

props: { 
    type:[Number,String],
    required:true
}