Что будет если скрестить React и Angular?


Akili — javascript фреймворк, который появился под влиянием таких решений как React, Angular, Aurelia и в меньшей степени некоторых других. Целью было объединить все лучшее, что я вижу в них и максимально все упростить.

Нравится React, но отталкивает JSX? Любите Angular, но надоела всякая магия?

Тогда вам стоит попробовать это.

Я убежден, что наилучший способ в чем-то разобраться это практика. Поэтому начну описание сразу же с примеров. Они написаны так, как если бы мы компилировали код с помощью Babel (es2015 + stage-0).

Первые шаги


import Akili from 'akili';

class MyComponent extends Akili.Component {
  constructor(el, scope) {
    super(el, scope);
    scope.example = 'Hello World';
  }
}

Akili.component('my-component', MyComponent); // регистрируем компонент

document.addEventListener('DOMContentLoaded', () => {
  Akili.init(); // инициализируем фреймворк
});

<body>
  <my-component>${ this.example }</my-component>
</body>

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

Во-первых, область видимости компонента разделена от области видимости разметки. То есть, можно спокойно наследовать компоненты и это никак не отразиться на этой самой разметке.

class MySecondComponent extends MyComponent  {
 constructor(...args) {
    super(...args);
    this.scope.example = 'Goodbye World';
  }
  myOwnMethod() {}
}

Akili.component('my-second-component', MySecondComponent)

<body>
  <my-component>${ this.example }</my-component>
  <my-second-component>${ this.example }</my-second-component>
</body>

За область видимости разметки отвечает свойство компонента scope. Это специальный объект, который вы можете заполнить необходимыми данными и отображать их в шаблонах с помощью выражений вида ${ this.example }, где this и есть этот самый scope. На самом деле в скобках может быть любое javascript выражение.

Во-вторых, области видимости разметки также наследуются. Добавим в scope первого компонента новое значение:

class MyComponent extends Akili.Component {
  constructor(el, scope) {
    super(el, scope);
    scope.example = 'Hello World';
    scope.test = 'Test';
  }
}

Тогда разметка ниже:

<body>
  <my-component>
     <b>${ this.example }</b>
     <my-second-component>${ this.example } - ${ this.test }</my-second-component>
 </my-component>  
</body>

После компиляции будет выглядеть как:

<body>
  <my-component>
     <b>Hello World</b>
     <my-second-component>Goodbye World - Test</my-second-component>
 </my-component>  
</body>

В-третьих, синхронизация логики компонента с его шаблоном происходит путем лишь изменения переменной scope в любой момент времени.

class MyComponent extends Akili.Component {
  constructor(...args) {
    super(...args);
    this.scope.example = 'Hello World';

    setTimeout(() => {
      this.scope.example = 'Goodbye World';
    }, 1000);
  }
}

Через секунду значение переменной изменится и в объекте и в шаблоне.

Lifecycle в двух словах, в сравнении с React


.constructor(el, scope)
Прежде всего, поскольку любой компонент это простой javascript класс, будет вызван конструктор. Он получает в аргументы html элемент, к которому будет привязан компонент и объект scope. Здесь вы можете делать с элементом любые изменения, либо отменить компиляцию, в случаи необходимости, вызовом метода .cancel().

.created()
Если компиляция компонента не была отменена, то вы попадаете сюда. Этот метод фактически ничем не отличается от конструктора. В React, похожую функцию выполняет componentWillMount.

.compiled()
Здесь компонент скомпилирован, в шаблонах вместо выражений уже соответствующие значения.
В React это componentDidMount. Вы имеете доступ ко всем родительским элементам, которые к этому моменту гарантированно скомпилированы тоже.

.resolved()
Этот метод, насколько я знаю, не имеет аналогов в известных мне фреймфорках.
Дело в том, что Akili позволяет использовать при компиляции асинхронные операции, если это нужно. К ним относятся некоторые системные и любые кастомные операции. Например, загрузка шаблона компонента из файла:

class MyComponent extends Akili.Component {
  static templateUrl = '/my-component.html';

  constructor(...args) {
    super(...args);
    this.scope.example = 'Hello World';
  }
}

Или любая асинхронная операция, которую мы выполним сами:

class MyComponent extends Akili.Component {
  static templateUrl = '/my-component.html';

  constructor(...args) {
    super(...args);
    this.scope.example = 'Hello World';
  }

  compiled() {
     return new Promise((res) => setTimeout(res, 1000));
  }
}

В методе compiled вы можете вернуть промис, тогда resolved будет ждать выполнения ВСЕХ асинхронных операций. При этом сама компиляции будет происходить синхронно.

Другими словами в методе resolved вы можете быть уверены, что скомпилированы абсолютно все дочерние элементы, любого уровня вложенности, в том, числе содержащие какие-либо асинхронные операции.

.removed()
Вызывается при удалении компонента. Аналог — componentDidUnmount.

.changed(key, value)
Вызывается при изменении любого атрибута компонента. Аналог — componentWillReceiveProps.
Это очень важная часть фреймфорка, поэтому опишу ее более подробно в отдельной секции ниже.

Универсальность, изоляция, модульность компонентов


Очень важно, чтобы компонент мог быть полностью изолирован и вообще не зависел от внешних условий. Вот пример такого компонента:

import Akili from 'akili';

class NineComponent extends Akili.Component {
  static template = '${ this.str }';

  static define() {
     Akili.component('nine', NineComponent);
  }
  constructor(...args) {
    super(...args);
    this.scope.str = '';
  } 
  compiled() {
     this.attrs.hasOwnProperty('str') && this.addNine(this.attrs.str);
  }
  changed(key, value) {
     if(key == 'str') {
        this.addNine(value);
     }
  }
  addNine(value) {
    this.scope.str = value + '9';
  }
}

Добавим его к предыдущим примерам:

import NineComponent from './nine-component';

NineComponent.define();
Akili.component('my-component', MyComponent); 

document.addEventListener('DOMContentLoaded', () => {
  Akili.init();
});

<body>
  <my-component>
     <nine str="${ this.example }"></nine>
  </my-component>  
</body>

Итак, вот что мы получим после компиляции:

<body>
  <my-component>
    <nine str="Hello World">Hello World9</nine>
  </my-component>  
</body>

Обратите внимание, NineComponent получился абсолютно обособленным. Он похож на функцию, которая может принимать какие-то аргументы и что-то с ними делать. В данном случаи просто добавляет цифру 9 в конец переданной строки и отображает ее.

Можно провести аналогию между атрибутами в Akili и свойствами в React.
this.attrs => this.props. Они выполняют одну и туже роль, но есть мелкие различия:

В Akili свойство attrs как и scope является Proxy, то есть можно добавить, изменить или удалить атрибут html элемента, делая соответствующие операции с каким-то свойством данного объекта. Свойства объекта attrs синхронизируются с атрибутами элемента.

Вы можете использовать атрибуты для биндинга. В примере выше, если переменная области видимости this.example компонента MyComponent изменится, то будет вызван метод changed у NineComponent. Обратите внимание, мы не сделали для этого ничего особенного. Выражение в атрибуте str ничем не отличается от примеров в начале, где мы просто отображали значение в шаблоне.

Для удобства можно использовать сокращенную версию changed.

class NineComponent extends Akili.Component { 
  changed(key, value) {
     if(key == 'str') {
        this.addNine(value);
     }
  }
}

class NineComponent extends Akili.Component { 
  changedStr(value) {
     this.addNine(value);
  }
}

Примеры выше эквиваленты. Чтобы не плодить гору ифов или кэйсов, проще писать сразу нужный метод. Принцип именования прост: changed + название атрибута кэмел кейсом с заглавной буквы.

События


Здесь все просто, добавляем тире после on, а дальше все как обычно. Изменим наш первоначальный пример:

class MyComponent extends Akili.Component {
  static events = ['timeout'];

  constructor(...args) {
    super(...args);
    this.scope.example = 'HelloWorld';
    this.scope.sayGoodbye = this.sayGoodbye;
  }
  compiled() {
      setTimeout(() => this.attrs.onTimeout.trigger(9), 5000);
  }
  sayGoodbye(event) {
      console.log(event instanceof Event); // true
      this.scope.example = 'Goodbye World';
  }
}

<body>
  <my-component on-timeout="${ console.log(event.detail); // 9 }">
    <button on-click="${ this.sayGoodbye(event) }">say goodbye</button>
    ${ this.example }
  </my-component>  
</body>

Система событий основана на нативной. В примере выше видно, что вы также можете создавать и вызывать свои кастомные события.

Работа с массивами


class MyComponent extends Akili.Component {
  constructor(...args) {
    super(...args);

    this.scope.data = [];

    for (let i = 1; i <= 10; i++) {
      this.scope.data.push({ title: 'value' + i });
    }
  }
}

<my-component>
  <for in="${ this.data }">
    <loop>${ this.loopIndex } => ${ this.loopKey} => ${ this.loopValue.title  }</loop>
  </for>
</my-component>

<my-component>
  <ul in="${ this.data }">
    <li>${ this.loopValue }</li>
  </ul>
</my-component>


Дополнительно


Из коробки Akili также имеет роутер, библиотечку для совершения ajax запросов, множество системных компонентов для работы с циклами, формами, возможность прикрутить серверный рендеринг и.т.д, в документации вы можете найти подробное описание.

Данная статься написана чтобы познакомить вас с Akili, я постарался раскрыть в целом какие-то технические моменты, но здесь не уместилась даже пятая часть того, что в себе содержит фреймворк. Гораздо больше информации есть в документации, ну и если будет интерес, то начну раскрывать тему глубже в других статьях.

Фреймворк пока в бете, пробуйте, смотрите )
Поделиться публикацией

Комментарии 67

    0
    class MySecondComponent extends MyComponent  {
     constructor(...args) {
        super(...args);
        this.scope.example = 'Goodbye World';
      }
      myOwnMethod() {}
    }

    Как в этом случае добавляются/описываются дополнительные зависимости для MySecondComponent?


    Во-вторых, области видимости разметки также наследуются.

    Прототайпинг скоупа как раз ангуляровская фишка (точнее обычный JS прототайпинг), от которой лучше отказаться, так же лучше отказаться от любых вещей завязанных на специфику фреймворка, передавать все явном виде через атрибуты. Компоненты по-моему мнению компоненты должны быть независимыми/изолированными.

      0
      1) Не совсем понял, что имеется ввиду под дополнительными зависимостями?
      2) Тут согласен, но это скорее просто бонус, разные ситуации бывают. Про то как сделать компоненты модульными я в статье описал.
    +6
    Если хочется React + Angular не лучше ли взять Vue.js?
      +4
       <for in="${ this.data }">
          <loop>${ this.loopIndex } => ${ this.loopKey} => ${ this.loopValue.title  }</loop>
        </for>

      Синтаксис так себе, интуитивно не понятный, по сути скрестили кота с ежом без без поддержки кота и ежа. И вызовы конструктора базового класса, тоже не удобно, нужны обертки. Сверху правы берите Vue и не мучайтесь

        0
        Весь синтаксис это доллар и фигурные скобки в стиле es6, причем во всех кейсах )
          0

          Доллар и фигурные скобки в стиле ES6, а стрелки — не в стиле ES6. Ну и зачем так путать?

            0
            Неудачный пример получился наверное, согласен ) Стрелки просто часть html
              0

              С каких пор стрелки — часть HTML?

                0

                Имелось в виду, что стрелки — часть выводимого HTML, они будут отображаться на странице.

                  0
                  да, именно )
        +5
        Именно! Vue — это то, каким должен был быть ангуляр.
          –1
          все популярные фреймворки суть одно и то же: крайне не организованный код и hardcoded html, которые невозможно использовать в другом проекте

          графический интерфейс очень прост и имеет простые стандартные элементы и функционал, поэтому кодирование бизнес логики не должно быть таким сложным

        –2
        Увидел stage-0 перестал читать дальше. Если stage-0 пускать в продакш, то так далеко не уехать.
          0

          Подозреваю, что автор просто не в курсе, что class fields уже давно не stage-0, а 2. Стадии показываются тут. Stage-2 будет достаточно, чтобы код из статьи собрался.


          Да и вообще, набор es2015+stage-0 это очень странно. То есть мы берем 2015, пропускаем 2016, 2017 (которые уже тоже часть стандарта и есть в некоторых браузерах), зато берем всякую дичь из stage-0.


          Сам Babel рекомендует использовать babel-preset-env, который будет обновляться по мере добавления новых фич в стандарт, и также будут выпиливаться преобразования для штук, которые уже нативно есть в браузерах (список поддерживаемых браузеров настраивается)

            0
            Можно собрать как удобно, просто хотел предупредить о свойствах класса в описании.
              –1

              Что-то я не стал бы доверять фреймворку, разработчик которого говорит "возьмите какие-нибудь настройки Babel", вместо минимально необходимого набора плагинов.

                0
                Суть фреймворка-то не в том как скомпилировать какое-то конкретное приложение, можно хоть в head его подключить и все будет работать.
                  0
                  Потому что это библиотека, а не фреймворк :).
          0
          Сайт лежит в 502-й. Видно не ожидали вы местного наплыва :)

          По теме: первое впечатление — Vue.js.
          Но, честно говоря, мне больше нравится именно React на который я пересел с Ангуляра (первого). В особенности нравится JSX за его 100% совместимость с JS. А все эти прилепленные директивы и циклы через html жутко неудобны, как по мне.

          В статье вы сначала пишите, что скрестили Ежа с Коноплей, но потом эта мысль как-то сразу теряется. В чем преимущества перед обоими фреймворками? Их потому и два, что они офигеть какие разные. И не нужно это менять.

          Кстати, везде в конструкторе присутствет super(...args);
          Нужно этого как-то избегать, либо добавить аналог componentDidMount(), а то забыл поставить — и что будет?
            0
            сайт лежал — обнаружил memory leak в jsdom, буду искать решение.

            аналог componentWillMount — created
            аналог componentDidMount — compiled

            То есть конструктор можно вообще и не писать.
            0

            Про шаблоны совсем ничего не написано. Как написать такой компонент, который из этого html:


            <hello-component name="Tester" description="test user" />

            сделает вот такой:


            <div>
              <h1>Hello, tester!<h1>
              <p>test user</p>
            </div>

            ?

              0
              class HelloComponent extends Akili.Component {
               static templateUrl = './path/to/template';
              }
              


              или

              class HelloComponent extends Akili.Component {
                static template = `<div>
                  <h1>Hello, tester!<h1>
                  <p>test user</p>
                </div>`;
              }
              
                0

                А что будет, если внутри HelloComponent будет разметка:


                <hello-component>Текст внутри</hello-component>

                Шаблон ее перезапишет или добавится в конец?

                  0
                  перезапишет, но если содержимое нужно куда-то вставить, то можно использовать свойство скоупа .__content

                  class HelloComponent extends Akili.Component {
                    static template = `<div>
                      <h1>Hello, tester!<h1>
                      <p>${ this.__content }</p>
                    </div>`;
                  }
                  


                  В приме выше выражение ${ this.__content } заменится на Текст внутри
              0
              .resolved() Этот метод, насколько я знаю, не имеет аналогов в известных мне фреймфорках.

              Не имеет аналогов, не потому что их разработчики не догадались об этом, а потому, что надо что-то показывать, пока компонет загружает свои зависимости (спиннер, например).


              В React это делается тривиально


              class ComponentWithLoader extends React.Component {
                state = { loading: false, data: null };
              
                componentDidMount() {
                   this.setState({loading: true})
                   loadData().then((data) => this.setState({loading: false, data: data}));
                }
              
                render() {
                  if(this.state.loading) {
                     return <Loader />
                  }
                  return <div>{/*какой-то контент*/}</div>
                }
              }

              При желании можно завернуть в переиспользуемый компонент, или взять уже готовый.
              Тащить это в ядро фреймворка смысла нет.

                0
                Смысл все же есть. Бывают, например, группы компонентов, когда их несколько и они завязаны друг на друге. Например посмотрите реализацию табов.

                Родительский компонент может захотеть что-то сделать с дочерними. Метод resolved гарантирует, что в нем все дочерние будут полностью скомпилированы и тогда к ним можно обратиться через систему коммуникации компонентов.
                  0

                  Посмотрел на реализацию табов, понятнее не стало. В исходном коде нет ни одной асинхронной операции, откуда там resolved нужен, совсем не ясно

                    0
                    Дело в том что компиляция идет сверху вниз по дереву, элемент за элементом, поэтому если нужно что-то сделать с дочерними элементами из родительского после его компиляции, то мы также используем resolved. В нем все дочерние компоненты будут гарантировано скомпилированы, в этом его смысл.

                    В целом, метод resolved используем когда нужен доступ к детям.

                    Такой лайфцикл позволяет работать с компонентами, почти так как это происходит в DOM:
                    В примерах ниже левая и правая части эквивалетны:

                    el.querySelector('input') => component.child('input')
                    el.querySelectorAll('input') => component.children('input')
                    el.parentNode => component.parent()

                    Разница только в том, что все методы справа возвращают не элемент, а компонент.
                    В компонентах Akili есть много разных методов для взаимодействия друг с другом

                    class ParentComponent extends Akili.Component {
                      resolved() {
                         let childComponent = this.child('child');
                    
                         console.log(childComponent.scope.example); //  'Hello World'
                    
                         childComponent.scope.example = 'Goodbye World'; // в разметке значение также поменяется
                      }
                    }
                    
                    class ChildComponent extends Akili.Component {
                      compiled() {
                        scope.example = 'Hello World';
                      }
                    }
                    
                    Akili.component('parent', ParentComponent); 
                    Akili.component('child', ChildComponent); 
                    

                    <parent>
                       <child>${ this.example }</child>
                    </parent>
                    


                      0

                      childComponent.scope.example = 'Goodbye World'; — про инкапсуляцию, видимо, никто не слышал… Ну нельзя же такие вещи приводить в качестве примера!

                        0
                        А в чем тут проблема? Компонент это по сути экземпляр класса, а scope это public property.
                          0

                          А с какого перепугу scope является public property?

                          +1
                          По хорошему, компонент должен быть «черным ящиком с парой кнопок» с мнимальным интерфейсом, что-б никто не мог внутрях ковырятся, иначе это будет повышать риск хаоса.
                  –2

                  А можно не заниматься ерундой с ручным управлением индикаторами ожидания, воспользовавшись реактивным программированием.


                  Ваш, код мог бы выглядеть примерно так:


                  class ComponentWithLoader extends MyComponent {
                  
                    @ $mol_mem()
                    render() {
                      return $mol_http.request( '/data.json' ).json().map( item => <Item item={ item } /> )
                    }
                  
                  }
                    +1

                    Так а что будет видеть пользователь, пока data.json загружается?

                      –1

                      Индикатор ожидания, очевидно. Не нравится стандартный, всегда можно запилить свой:


                      class ComponentWithLoader extends MyComponent {
                      
                        @ $mol_mem()
                        render() {
                          try {
                            return $mol_http.request( '/data.json' ).json().map( item => <Item item={ item } /> )
                          } catch( error ) {
                            return <StatusIndicator error={ error } />
                          }
                        }
                      
                      }
                        0

                        А каким образом неперехваченное исключение превращается в индикатор ожидания?

                          0

                          Точно таким же try-catch, но там, где вызывается render (это не в реакте).

                          0

                          Что-то это еще больше все запутывает


                          catch блок — это про ошибку после загрузки. А в процессе что будет показываться?

                            0

                            У него в фреймворке состояние "в процессе" считается исключительным. Метод render вычисляется два раза, первый раз отваливается с исключением, а второй раз запускается автоматически когда запрос выполнится. В этот раз метод request не будет делать нового запроса к серверу, а вернет значение, полученное в прошлый раз.


                            По-своему красивая идея — жаль только метод request делает не то как называется.

                              0

                              Метод с аннотацией mol_mem (мемоизация, как я предполагал), вызывается несколько раз и выдает разный результат?


                              Извините, но мне с таким подходом точно не по пути.

                                0

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


                                В Knockout такая штука называется pureComputed, в MobX — computed.

                    –3

                    Как по мне, jsx шикарен, а сам react невероятно элегантен. Нет ни одной задачи, которой я не смог бы решить с его помощью или с помощью библиотеки, которую можно к нему прикрутить.


                    В любом случае, библиотека хорошая, "но использовать я ее, конечно, не буду". По крайней мере к реакту у меня доверия всяко больше. Как минимум, ответов на stack overflow больше.


                    Желаю дальнейших успехов в разработке)

                      –1
                      Это всё конечно прекрасно, только вот не совсем понятно зачем всё это. Кто хотел получить Angular + React, получили Vue, иногда мне кажется, что она только для этого и придумана была. Но это, очередной проходной фреймворк.
                        0
                        У вас получился Polymer. Пока чуть менее сложный, но это вы ещё до dom-repeat, обработки массивов, атомарных изменений нескольких полей и оптимизации вычисляемых байндингов не дошли. Ну и без Shadow DOM, HTML-imports и изоляции CSS у вас реализация. А так — один в один «стиль» «фреймворка» (правильнее — библиотеки). Polymer себя позиционирует таки компонентной библиотекой, и вам следует тоже, ибо «простота» и «отсутствие магии» — это и есть отсутствие навязываемой жёсткой структуры проекта, предлагается лишь способ «нарезки» кода на компоненты, а архитектуру из этих компонентов программисту придётся сочинять самостоятельно. Ну и ценность таких библиотек зависит от их заполненности «подходящими» друг к другу как пазлинки готовыми базовыми компонентами, и тут Polymer вас тоже сильно опережает, простой чат (при готовом бэке) можно собрать вообще без кода, только путём связывания атрибутов готовых компонентов в разметке друг с другом (там есть «невизуальные» компоненты типа компонента обеспечивающего роутинг или AJAX-запросы к серверу).

                        Призываю присоединиться к Polymer, работы там ещё куча :).
                          0
                          (Прошу прощения, dom-repeat и массивы у вас поддерживаются, роутинг и аякс-запросы тоже в готовых компонентах предложены, поторопился комментировать — теперь я уверен на 100%, что вы вдохновлялись Полимером :))
                          –1
                          > Что будет если скрестить React и Angular?

                          Reangular? Anact?
                            0
                            Regular =) Была идея так назвать… )
                            0

                            Что-то, как мне кажется, тут была нарушена сама суть понятия "компонент". Компонентом применительно к UI обычно называют обособленную часть интерфейса, обладающую своим [внешним] видом, состоянием и поведением.


                            Здесь же "шаблонная" часть компонента вытащена наружу, компоненту остались только состояние и поведение. Это уже не компонент получается, а контроллер из старого AngularJS.

                              0
                              Компонент = логика + шаблон + имя. По имени один компонент может использовать в своём шаблоне другие компоненты. Всё нормально тут с компонентностью, вроде. (Упомяну опять «свой любимый» Polymer, в нём благодаря HTML-imports действительно более «железобетонно» «нарезаются» компоненты, HTML является контейнером и для разметки, и для скриптов, и для стилей, которые, конечно, можно разнести и на отдельные файлы, оставив в HTML ссылки на них. Плюс ко всему этому получается проще сборка — tree-shaking становится действительно tree — сборщик-«вулканизатор» напрямую из построенного импортами DOM-дерева получает всю иерархию зависимостей без необходимости анализировать JS-код.)
                                0
                                Компонент = логика + шаблон + имя.

                                Покажите мне шаблон у вот этого компонента:


                                class MyComponent extends Akili.Component {
                                  constructor(el, scope) {
                                    super(el, scope);
                                    scope.example = 'Hello World';
                                  }
                                }
                                  +1
                                  Ничего страшного, если шаблон является опциональным аспектом компонента (для организации чего-нибудь типа HOC из Реакта или Behaviors из Полимера, например :)). Компонент не обязан быть визуальным.
                              +2

                              Для решения подобных задач, навскидку, на ум приходят варианты сделать это с помощью нативных кастомных элементов или Polymer 2 или Vue.js ...etc. Что я должен знать о Akili, чтобы рассматривать его в качестве одной из альтернатив? В представленном описании я ничего такого не увидел, что я упускаю?

                                +3
                                • C react сравнили, с angular тоже, а по что aurelia обидели?
                                • Какие проблемы вы решали и решили?
                                • Какие будут аргументы против фразы "yet another framework"?
                                • Что с перфомансом, где бенчи?
                                • Ну и, наконец, где работающий туду-лист?
                                  0
                                  Примитивный todo есть на главной странице, хотя довольно многословен.
                                  0
                                  Через секунду значение переменной изменится и в объекте и в шаблоне.
                                  Как отслеживается изменения?

                                  Работают и отслеживаются ли «js» выражения в шаблоне?, наподобии
                                  ${a+b + ' ' + foo(c) + bar()}


                                  Зачем нужен scope если есть this? особенно если оно «смешивается» в шаблоне.

                                      <for in="${ this.data }">
                                  

                                  Можно ли сделать вложенный цикл и использовать данные родительского цикла во внутреннем?
                                    +1
                                    Как отслеживается изменения?

                                    Изменения отслеживаются с помощью механизма Proxy.

                                    Работают и отслеживаются ли «js» выражения в шаблоне?

                                    Да, отслеживаются все выражения где есть хоть какая-то переменная скоупа

                                    Зачем нужен scope если есть this?

                                    this в html это и есть scope. Поскольку скоуп был придуман как область видимости разметки, то в ней он является контекстом. В компоненте же есть ссылка на на него, в свойстве scope.

                                    Можно ли сделать вложенный цикл и использовать данные родительского цикла во внутреннем?

                                    Да, каждый скоуп имеет свойство .__parent — ссылку на родительский

                                    Также, подробное описание всех возможностей, включая некоторые тонкости, можно найти в документации.
                                      +1
                                      Изменения отслеживаются с помощью механизма Proxy.
                                      ok, оно есть в 72% браузеров, в IE вероятно не появится никогда (в edge оно есть).

                                      this в html это и есть scope.
                                      Выглядит как лишняя сущность, было бы красивее разместить данные в this он бы и был this в html.

                                      Да, отслеживаются все выражения где есть хоть какая-то переменная скоупа
                                      Даже не так — если меняется любая отслеживаемая переменная, то вы делаете полный dirty-checking — проверяете все отслеживаемые переменные. При этом если данные в scope меняются, которые выводятся через функцию ${this.fullName()} — то обновления не происходит, недоработка.

                                      Итого: Идет проверка всего на каждое изменение — повышенная нагрузка, хотя Proxy позволяет реагировать точечно, с другой стороны эта «проверка всего» пропускает некоторые типы биндингов в html — хотя у vue.js такая же проблемма, видимо не сильно напрягает, и третье Proxy не поддерживается больщой долей браузеров, как результат — рановато для боя.

                                      Но для старта неплохо, все фреймворки с чего-то начинали.

                                      Кстати, если при вызове выражения биндингов будете передавать this как параметр вместо подмены this, то они будут работать на прядок быстрее.
                                        0
                                        Выглядит как лишняя сущность, было бы красивее разместить данные в this он бы и был this в html.

                                        Не совсем, в выражениях может быть что угодно, хоть ${ console.log('Hello') } хоть ${ window.location.href }
                                        Область видимости по умолчанию весь window. Если нужно изменить это поведение, то достаточно дописать метод Component.parse как вам надо.
                                        Даже не так — если меняется любая отслеживаемая переменная, то вы делаете полный dirty-checking — проверяете все отслеживаемые переменные. При этом если данные в scope меняются, которые выводятся через функцию ${this.fullName()} — то обновления не происходит, недоработка.

                                        Данные которые будут в функции тоже начнут отслеживаются. Слежка происходит не на уровне парсинга этой строки. Тут все гораздо хитрее.

                                        И еще момент, хоть отслеживается и каждое свойство скоупа отдельно, но синхронизация с шаблоном происходит группами. То есть если пройтись циклом и изменить 1000 значений в скоупе, то произойдет всего 1 операция изменения разметки, а не 1000.

                                          +1
                                          Данные которые будут в функции тоже начнут отслеживаются. Слежка происходит не на уровне парсинга этой строки. Тут все гораздо хитрее.
                                          Что-то не работает: http://jsfiddle.net/lega911/kw3f2mx2/ — fullName не обновляется.

                                          Странно, в другом примере у меня было полное сканирование, в этом нет.
                                          Область видимости по умолчанию весь window.
                                          Это не желательно, т.к. в шаблон может попасть всякая бяка из вне.
                                            –1
                                            Да, по поводу биндинга функции в шаблоне вы правы. Я в своем время долго решал какой вариант оставить. Почему-то запомнилось как будто оставил вариант с учетом всех вызовов.

                                            Сейчас прикинул все варианты и вернулся к тому же. Выполнять функцию снова все-таки лучше при изменении аргументов, а не содержимого тела.

                                              0
                                              Хотя я все равно не уверен, возможно добавлю такую фичу.
                                                0
                                                Спасибо за концентрацию внимания на этом моменте, я добавил возможность биндинга функции в шаблоне и по изменению аргументов и по телу. Теперь ваш пример должен работать.
                                        –1
                                        Посмотрел примеры, вы создали странный vue 2.

                                        Это было написано просто для веселья?
                                        Возможно, Вам стоит пересмотреть парадигму разработки, придумать что-то новое, мне это кажется интереснее, чем соединять готовые фреймворки.

                                        image
                                          0
                                          Нравится React, но отталкивает JSX? Любите Angular, но надоела всякая магия?

                                          Vue.js вам в помощь.

                                          Кстати, в Ангуляре (который .io), как по мне, минимум магии. В отличии от оверхайпнутого Реакта.

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                          Самое читаемое