Улучшение частей многостраничного приложения с помощью react или vue

я разрабатываю приложение с java & hibernate & spring mvc на стороне сервера и с помощью jquery на стороне клиента (не СПА).

теперь на странице поиска я использую ajax и получаю только json ответ, но я не хочу писать что-то подобное ниже в каждом запросе поиска или разбиения на страницы.

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

Я думаю, что это простой в использовании jsx С react или vue компонент просто на этой странице, чтобы обновить результаты.

я хочу также повторно использовать некоторые HTML-блоки и я думаю, что это будет легко с react или vue

я раньше немного строил СПА и npm и webpack и связывание, но я действительно не хочу использовать их, так как у меня есть Multi-приложения в разделе и это очень подходит для моего проекта.

Я думаю то же самое facebook делает, они используют react но facebook не СПА.

как я могу достичь этого гибридного подхода ?

4 ответов


я делал подобные вещи в прошлом. Я ввел небольшой реагирующий компонент в DOM.

вот как я сделал это:

создайте компонент React в JSX, назовем его 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

render ()

Render ReactElement в DOM в поставляемом контейнере и возвращает ссылку на компонент.

если ReactElement был ранее отображен в контейнер, это будет выполнять обновление на нем и только мутировать DOM по мере необходимости отразить последний компонент React.

renderToStaticMarkup ()

Это не создает дополнительные атрибуты DOM, такие как data-react-id, которые Реагируют использует внутренне. Это полезно, если вы хотите использовать React как простой статический генератор страниц, как удаление дополнительных атрибутов можно сохранить много байтов.


так как у вас есть существующее многостраничное приложение без шаг сборки (то есть без webpack/babel), я считаю, что один очень простой способ достижения того, что вы хотите, - это использование Vue.js.

вы можете определить шаблон и обновлять только данные.

вот демонстрация того, как вы бы сделали код, который вы показали в вопросе:

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>

в этом примере мы есть:

  • метод fetchUsers который будет выполнять вызов ajax;
  • на fetchUsers метод привязан к click событие <button> via @click="methodName" (это сокращение от v-on:click="methodName").
  • A v-if (v-if="ajaxDataAvailable") что составляет .search-container div скрыт до ajaxDataAvailable недвижимость true.
  • визуализация некоторых данных в шаблоне с помощью интерполяции:{{ ajaxData.title }} обратите внимание, что это берет значение из объектов, объявленных в data: часть экземпляра Vue (new Vue({... код) ниже и составляет автоматически обновляться всякий раз, когда ajaxData.title изменения (что происходит внутри fetchUsers метод при завершении вызова Ajax.
  • отображение списка с помощью v-for: v-for="result in ajaxData.results". Это повторяется в ajaxData.results массив, который слишком обновлен внутри fetchUsers метод.
  • использование <input> С элементом v-model директива, которая позволяет нам редактировать result.name значение напрямую (который также автоматически обновляет шаблон).

есть гораздо больше, чтобы Vue, это просто пример. При необходимости можно сделать более подробные демонстрации.

насколько интеграция в существующее приложение, вы можете вставить этот самый код на любую HTML-страницу, и он уже будет работать, нет необходимости в webpack/babel вообще.


Итак, есть две вещи, которые вы могли сделать, чтобы повторно использовать код:

  • Я бы рекомендовал React для совместного использования кода в качестве компонентов. Эта страница от официального docs объясняет, как использовать react с jquery. Дополнительные ресурсы для интеграции react и jquery jQuery-ui с react, использование react и jquery вместе, реагировать-тренинг
  • или используйте некоторый движок шаблонов, чтобы вам не нужно было проходить проблема интеграции новой библиотеки и ее работы вместе с jquery. Это так ответ предоставляет множество вариантов для этого.

Если вы не планируете переносить приложение jquery для реакции в долгосрочной перспективе, я бы не рекомендовал использовать react только для одной страницы. Было бы проще пойти по маршруту template engine.


от взглядов требования, вам как раз нужно:

  1. динамические, управляемые данными HTML-блоки
  2. , которые должны быть многоразовые

в этом случае, поскольку нам не нужно состояние, наличие всей структуры, такой как react/vue/angular, может быть излишним.

моя рекомендация будет идти шаблонизатора как jQuery Шаблоны плагин или руль

вы даже можете сохранить HTML блоки как отдельные многоразовые модули, которые вы можете вызывать по мере необходимости на своих страницах.

образец с помощью руля:

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);
})
<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>

Примечание:

одним из недостатков использования этого подхода (в отличие от структуры, такой как react/vue/angular) является то, что вам нужно будет обрабатывать привязку и разматывание событий вручную. Вы можете в некоторой степени смягчить это, обернув шаблоны в функцию, которая монтирует и размонтирует их автоматически.

// 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();
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js"></script>

<div id="target"></div>