使用react或vue增强多页面应用程序的各个部分

时间:2018-04-22 13:05:49

标签: javascript jquery reactjs vue.js

我正在开发一个java&的企业应用程序。 hibernate&服务器端spring mvc并在客户端使用jquery(不是SPA)。

现在在搜索页面中,我使用ajax并仅获得json响应,但我不想在每个搜索或分页请求中写下面这样的内容。

function(ajaxData) {
    ....
    $('#search').html('' +
        '<div class="search-container">' + 
          '<div class="search-item">' +
             '<div class="title-item">'+ajaxData.title+'</div>' + 
             ...
             ...
          '</div>' + 
        '</div>'
    )
    ....
}

我认为在此页面中使用jsxreact 组件很容易使用vue来刷新结果。

我还想重用一些html块,我认为reactvue

会很容易

我曾经建立了一个小的 SPA 项目,所有关于npmwebpack和捆绑,但我真的不想使用它们,因为我有一个多页应用,非常适合我的项目。

我认为facebook正在做同样的事情,他们使用反应,但facebook不是SPA。

我如何实现这种混合方法?

4 个答案:

答案 0 :(得分:6)

过去我做过类似的事情。我在DOM中注入了一个小的反应组件。

我是这样做的:

在JSX中创建一个React组件,我们称之为Demo

export class Demo extends React.Component {
    render() {
        return <h1>This is a dummy component.</h1>
    }
}

现在使用renderToStaticMarkup函数获取静态html。

const staticMarkup = renderToStaticMarkup(<Demo PASS_YOUR_PROPS/>);

您拥有HTML,现在可以使用innerHTML在所需位置插入此标记。

如果我误解了你的问题,请道歉。

更新

我们也可以将render()用于此目的。例如:

document.getElementById("button").onclick = () => {
  render(
    <Demo PASS_YOUR_PROPS/>,
    document.getElementById("root")
  );
};

使用render()和renderToStaticMarkup的工作解决方案:https://codesandbox.io/s/w061xx0n38

渲染()

  

将ReactElement渲染到提供的容器中的DOM中   返回对组件的引用。

     

如果ReactElement先前已经渲染到容器中,那么这个   将对其执行更新,并仅根据需要改变DOM   反映最新的React组件。

renderToStaticMarkup()

  

这不会创建额外的DOM属性,例如data-react-id   React在内部使用。如果要将React用作a,这非常有用   简单的静态页面生成器,剥离额外的属性   可以节省很多字节。

答案 1 :(得分:6)

由于您现有的多页应用程序没有构建步骤(即没有webpack / babel),我相信一种非常简单的方法来实现您想要的是使用Vue.js. / p>

您可以定义模板并仅更新数据。

以下是您将如何处理问题中显示的代码的演示:

new Vue({
  el: '#app',
  data: {
    ajaxDataAvailable: false,
    ajaxData: {
      title: '',
      results: []
    }
  },
  methods: {
    fetchUsers() {
      this.ajaxDataAvailable = false; // hide user list
      $.getJSON("https://jsonplaceholder.typicode.com/users", (data) => {
        this.ajaxData.title = 'These are our Users at ' + new Date().toISOString();
        this.ajaxData.results = data;
      	this.ajaxDataAvailable = true; // allow users to be displayed
      });
    }
  }
})
/* CSS just for demo, does not affect functionality could be existing CSS */
.search-container { border: 2px solid black; padding: 5px; }
.title-item { background: gray; font-weight: bold; font-size: x-large; }
.result-item { border: 1px solid gray; padding: 3px; }
<script src="https://unpkg.com/vue"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

<div id="app">
  <button @click="fetchUsers">Click to fetch the Users</button><br><br>

  <div class="search-container" v-if="ajaxDataAvailable">
    <div class="search-item">
      <div class="title-item"> {{ ajaxData.title }}</div>
      <div class="result-item" v-for="result in ajaxData.results">
        Name: {{ result.name }} - Phone: {{ result.phone }} - Edit name: <input v-model="result.name">
      </div>
    </div>
  </div>

</div>

在这个例子中,我们有:

  • 将执行ajax调用的方法fetchUsers;
  • fetchUsers方法绑定到click的{​​{1}}事件<button>@click="methodName"的简写)。
  • v-on:click="methodName"v-if)隐藏v-if="ajaxDataAvailable" div,直到.search-container属性为ajaxDataAvailable
  • 使用插值在true中渲染模板中的某些数据,请注意,这会从Vue实例的{{ ajaxData.title }}部分中声明的对象中选择值(data:代码在new Vue({...发生变化时(在ajaxData.title方法中,当Ajax调用完成时会发生什么),自动更新。
  • 使用fetchUsers呈现列表:v-for。这在v-for="result in ajaxData.results"数组中进行迭代,在ajaxData.results方法中进行了更新。
  • fetchUsers元素与<input>指令的使用,允许我们直接编辑v-model值(也会自动更新模板)。

Vue还有很多,这只是一个例子。如果需要,可以进行更详细的演示。

集成到现有应用程序而言,您可以将此代码粘贴到任何HTML页面中,它已经可以正常工作,无需任何webpack / babel。

答案 2 :(得分:4)

因此,您可以做两件事来重复使用代码:

  • 我建议React将代码共享为组件。官方docs的这个页面解释了如何使用jquery做出反应。 用于集成react和jquery jquery-ui with reactUsing react and jquery togetherreact-training
  • 的其他资源
  • 或者,使用一些模板引擎,这样您就不必经历集成新库并使其与jquery一起工作的麻烦。这个SO answer为此提供了很多选择。

除非您计划从长远来看迁移您的jquery应用程序做出反应,否则我不建议仅针对一个页面使用react。使用模板引擎路径会更容易。

答案 3 :(得分:2)

从要求的外观来看,你只需要:

  1. 动态,数据驱动的HTML块
  2. 哪些需要重复使用
  3. 在这种情况下,由于我们不需要状态,因此使用像react / vue / angular这样的整个框架可能会有点过分。

    我的建议是选择像jQuery Templates PluginHandlebars

    这样的模板引擎

    您甚至可以将HTML块存储为单独的可重用模块,您可以根据需要在页面中调用这些模块。

    使用Handlebars的示例:

    &#13;
    &#13;
    var tmpl = Handlebars.compile(document.getElementById("comment-template").innerHTML);
    
    function simulatedAjax(cb){
      setTimeout(function(){
        cb(null, {title:'First Comment', body: 'This is the first comment. Be sure to add yours too'});
      },2000);
    }
    
    
    simulatedAjax(function(err, data){
      if(err){
        // Handle error
        return;
      }
      document.getElementById('target').innerHTML = tmpl(data);
    })
    &#13;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js"></script>
    
    <div id="target">
    Loading...
    </div>
    
    <script id="comment-template" type="text/x-handlebars-template">
      <div class="comment">
        <h1>{{title}}</h1>
        <div class="body">
          {{body}}
        </div>
      </div>
    </script>
    &#13;
    &#13;
    &#13;

    注:

    使用此方法的一个缺点(与react / vue / angular等框架相反)是您需要手动处理事件绑定和解除绑定。您可以通过将模板包装在一个自动安装和卸载它的函数中来缓解这种情况。

    &#13;
    &#13;
    // Single reuable JS file for each component
    (function(namespace) {
      var _tmpl = Handlebars.compile('<div class="comment"><h1>{{title}}</h1><p>{{body}}</p></div>');
    
      function titleClickHandler(ev) {
        alert(ev.target.innerHTML)
      }
    
      function CommentWidget(target, data) {
        var self = this;
        self.data = data;
        self.target = document.querySelector(target);
      }
      CommentWidget.prototype.render = function() {
        var self = this;
        self.target.innerHTML = _tmpl(self.data);
    
        // Register Event Listeners here
        self.target.querySelector('h1').addEventListener('click', titleClickHandler)
    
      }
      CommentWidget.prototype.unmount = function() {
        var self = this;
        // Unregister Event Listeners here
        self.target.querySelector('h1').removeEventListener('click', titleClickHandler);
    
        self.target.innerHTML = '';
    
      }
    
      window._widgets.CommentWidget = CommentWidget;
    
    })(window._widgets = window._widgets || {})
    
    
    // Usage on your page 
    var w = new _widgets.CommentWidget('#target', {
      title: 'Comment title',
      body: 'Comment body is remarkably unimaginative'
    });
    
    // Render the widget and automatically bind listeners
    w.render();
    
    // Unmount and perform clean up at a later time if needed 
    //w.unmount();
    &#13;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js"></script>
    
    <div id="target"></div>
    &#13;
    &#13;
    &#13;