在没有 Angular 的情况下将 UI 路由器状态解析为 URL

Posted

技术标签:

【中文标题】在没有 Angular 的情况下将 UI 路由器状态解析为 URL【英文标题】:Parsing UI router states to URLs without Angular 【发布时间】:2017-11-09 17:30:10 【问题描述】:

我有一个 Angular 1.5.9 Web 应用程序和一个 Node.js/Sails.js 0.12 后端。 在 Angular 内部运行 UI 路由器 0.4 来处理状态。

状态定义可能看起来像这样(我会说很普通):

$stateProvider.state('dogs', 
            url: '/ourdogsarecute_specialIDofDog
        ).
        state('dogs.specialDogState', 
            url: '/specialinfo_specialInfoOfDog'
        );

现在,出现以下情况:在后端(即 Angular 之外),我必须转换 Angular UI 路由器状态链接,例如 stateName: 'dogs.specialDogState', stateParams: specialIDofDog: 11212, specialInfoOfDog: 'likesbones' 转换为有效的 URL,例如 https://www.our-app.dog/ourdogsarecute_11212/specialinfo_likesbones

如果没有大量的手工工作,我不知道如何做到这一点。是否有一种将 UI 路由器状态作为节点模块的解析器?

我可以以某种方式从后端访问状态定义所在的前端代码。那不是问题。问题是从状态链接到 URL 的转换。

【问题讨论】:

【参考方案1】:

UI-Router 1.0 将代码拆分为 ui-router core 和 ui-router angularjs。您可以在节点后端使用 ui-router 核心(没有外部依赖项)来生成这些 url。由于您已经将状态作为 JSON 文件提供,您只需在后端使用 ui-router 核心注册状态,然后使用状态对象生成 URL。

在你的节点后端,添加 ui-router 核心

npm install --save @uirouter/core

// The library exports most of its code
var UIR = require('@uirouter/core');

// Create the router instance
var router = new UIR.UIRouter();
// Get the state registry
var registry = router.stateRegistry;

var states = [
   name: 'dogs', url: '/ourdogsarecute_specialIDofDog' ,
   name: 'dogs.specialDogState', url: '/specialinfo_specialInfoOfDog' ,
];

states.forEach(state => registry.register(state));

var params =  specialIDofDog: '11212', specialInfoOfDog: 'lovesbones' ;

// Get the internal state object
var stateObj = registry.get('dogs.specialDogState').$$state();
// Generate the URL
console.log(stateObj.url.format(params));

【讨论】:

谢谢!作品。但是,我想,您的意思是 npm install --save @uirouter/core 而不是 npm add --save @uirouter/core【参考方案2】:

供参考:我的解决方案现在看起来像这样。 首先,我将我的状态定义放到一个单独的文件中,以便从外部访问它:

var myStates = [
    
        name: 'dogs', stateProperties: 
        url: '/ourdogsarecute_specialIDofDog'
    
    , 
        name: 'dogs.specialDogState', stateProperties: 
            url: '/specialinfo_specialInfoOfDog'
        
    ];

然后在我的 app.config 中

for(var i = 0; i < myStates.length; i++) 
            $stateProvider.state(myStates[i].name, myStates[i].stateProperties);
        

在后端,我创建了这个函数:

/**
   * @description Turns state name and state params into a URL string, using stateLinks definition synchronized from front end (being UI router state definitions)
   * @param string  stateName Something like 'dogs.info.specialAttributes'
   * @param object  stateParams Something like dogID: 34346346, dogStatus: 'private', dogInfo: 'food'
   * @returns string URL
   */
  stateLinkResolve: function(stateName, stateParams) 

    if(!(stateName && stateName.length > 0)) 
      return '/';
    

    var resultUrl = '';

    var splittedSubStates = stateName.split('.');// split "dogs.info.specialAttributes" into ["dogs","info","specialAttributes"]

    var currentStateInHierarchy = '';
    for(var i = 0; i < splittedSubStates.length; i++) 

      /* Add dot if "in between": not the first, not the last. So that "dogs" remains "dogs", but when going to "dogs.info", we want the dot in between */
      if(i > 0 && i < (splittedSubStates.length + 1) ) 
        currentStateInHierarchy += '.';
      
      currentStateInHierarchy += splittedSubStates[i]; // Add current splitted name (being only the last name part) to the state name in its context. I.e. when doing "info", we want to access "dogs.info"
      var currState = _.find(stateDefs,name: currentStateInHierarchy);
      var urlRaw = currState.stateProperties.url;

      /* uiRouter URLs may contain wildcards for parameter values like /ourdogs_dogID:int_dogStatus/:dogInfo.
        We go through each of these three types and replace them with their actual content.
          */
      for(var currentParam in stateParams) 
        urlRaw = urlRaw.replace(':' + currentParam, stateParams[currentParam]); // search for ":paramName" in URL
        urlRaw = urlRaw.replace('' + currentParam + '', stateParams[currentParam]); // search for "paramName" in URL

        // search for "paramName:paramType" in URL
        var uiRouterParamTypes = ["hash", "string", "query", "path", "int", "bool", "date", "json", "any"];
        for(var j = 0; j < uiRouterParamTypes.length; j++) 
          urlRaw = urlRaw.replace('' + currentParam + ':' + uiRouterParamTypes[j] + '', stateParams[currentParam]);
        
      
      resultUrl += urlRaw;
    
    return resultUrl;
  

问题是:这对于边缘情况可能会失败,而对于 UI 状态路由器的新功能以及在那里构建 URL 的方式肯定会失败。所以,还是希望能有一个直接使用UI路由魔法的解决方案。

【讨论】:

以上是关于在没有 Angular 的情况下将 UI 路由器状态解析为 URL的主要内容,如果未能解决你的问题,请参考以下文章

Angular - 在没有 jQuery 的情况下将行号添加到 textarea

如何在没有休息调用的情况下将 php json 变量分配给 angular?

Objective-C/CocoaHTTPServer - 是不是可以在没有任何 UI 的情况下将 CocoaHTTPServer 作为后台应用程序运行?

如何在不显示第一个组件的情况下将组件路由到另一个组件? - 角

如何在没有 UI 挂起的情况下将 QtcpSockets 连接到大约 100 个服务器?

如何在没有登录表单的情况下将摘要身份验证与 asp.net web api 和 angular js 一起使用?