Alpine.js on a concrete example

You may already have heard of Alpine.js. If not, then this is "Vue.js at the minimum." "Angular 1 for Millennials." Call it what you want, the main thing that you understand.


Why do we need another framework? Well, Alpine fits well in its niche. In fact, it is an alternative to large frameworks for sites where these large frameworks are not needed. For example, me, a trendy web developer, was harnessed to write a multi-page site. I need to make a form elementary and any other interactive. What will i do? I’ll take jQuery - friends don’t understand, on pure JS writing everything is also not comme il faut. In addition, I already know the reacts, angulars and view, I know what a data-driven approach is. How do I now store data before sending in HTML?


Here Alpine.js comes to the rescue. You can, of course, screw Vue or React. But React without JSX no one in their right mind would write, and Vue minified via CDN weighs 34 kB (versus 8.1 kB for Alpine). So it turns out that the choice falls on Alpine.


Recently here on HabrΓ© there were already familiarization articles about Alpine.js . Apart from the fact that the site cut out references to the template tag everywhere, the articles turned out to be quite good.


In order not to repeat myself, I will not retell the documentation , since it is very short (the whole framework is 13 directives and 6 magic properties) and will soon be available in Russian (at the time of writing, the translation is under the approval of the creator, but it’s already can be read in my fork ).


If you are interested and / or not familiar with Vue, I highly recommend it. For those who are familiar with Vue, a brief description of the key differences:


  • Instead, we v-use x-, i.e. not v-model, but x-model; not v-bind, but x-bindwhy? This is your homework :)
  • x-if x-for template. Virtual DOM.
  • {{}} . x-text x-html, Vue.

.


, . . - ? – . – , , . – " , " .. ..


, , .


HTML, CDN Alpine


<!DOCTYPE html>
<html lang="ru">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>To-Do  Alpine.js</title>
    <script
      src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.3.5/dist/alpine.min.js"
      defer
    ></script>
  </head>
  <body></body>
</html>

Alpine , . .


, ? . x-data.


<div x-data="{ name: '' }">
  <p>, <span x-text="name"></span></p>
</div>

<div> , . name <div> .


, to-do. :


<div
  x-data="{ todos: [{id: 1, title: ' ', completed: false}, {id: 2, title: ' ', completed: false}, {id: 3, title: '  ', completed: false}, {id: 4, title: '  ', completed: false}] }"
>
  <h1>  :</h1>
  <ul>
    <template x-for="todo in todos" :key="todo.id">
      <li x-text="todo.title"></li>
    </template>
  </ul>
</div>

. , , CSS- .completed, x-bind:class ( {[ ]: []}). cursor: pointer li, .


<style>
  .completed {
    text-decoration: line-through;
  }

  li {
    cursor: pointer;
  }
</style>

<div
  x-data="{ todos: [{id: 1, title: ' ', completed: false}, {id: 2, title: ' ', completed: false}, {id: 3, title: '  ', completed: false}, {id: 4, title: '  ', completed: false}], toggleTodo: function(id) { var todo = this.todos.find((todo) => todo.id === id); todo.completed = !todo.completed; } }"
>
  <h1>  :</h1>
  <ul>
    <template x-for="todo in todos" :key="todo.id">
      <li
        x-text="todo.title"
        @click="toggleTodo(todo.id)"
        :class="{'completed': todo.completed}"
      ></li>
    </template>
  </ul>
</div>

, , . , x-data :


<div x-data="todos()">
  <h1>  :</h1>
  <ul>
    <template x-for="todo in todos" :key="todo.id">
      <li
        x-text="todo.title"
        @click="toggleTodo(todo.id)"
        :class="{'completed': todo.completed}"
      ></li>
    </template>
  </ul>
</div>

<script>
  function todos() {
    return {
      todos: [
        { id: 1, title: ' ', completed: false },
        { id: 2, title: ' ', completed: false },
        { id: 3, title: '  ', completed: false },
        { id: 4, title: '  ', completed: false },
      ],
      toggleTodo: function (id) {
        var todo = this.todos.find((todo) => todo.id === id);
        todo.completed = !todo.completed;
      },
    };
  }
</script>

… Vue.


input :


<div x-data="todos()">
  <!-- ... -->
  <div>
    <h4>  :</h4>
    <input type="text" x-model="inputValue" />
    <button @click="addTodo()"></button>
  </div>
</div>

<script>
  function todos() {
    return {
      // ...
      inputValue: '',
      addTodo: function () {
        if (!this.inputValue) {
          return;
        }

        this.todos.push({
          id: Date.now(),
          title: this.inputValue,
          completed: false,
        });
        this.inputValue = '';
      },
    };
  }
</script>

push() , Alpine , - .


– . <li> span: , – .


<ul>
  <template x-for="todo in todos" :key="todo.id">
    <li @click="toggleTodo(todo.id)" :class="{'completed': todo.completed}">
      <span x-text="todo.title"></span>
      <span @click="deleteTodo(todo.id)">&times;</span>
    </li>
  </template>
</ul>

<script>
  function todos() {
    return {
      // ...
      deleteTodo: function (id) {
        this.todos = this.todos.filter((todo) => todo.id !== id);
      },
    };
  }
</script>

.


, , , REST API. , JSON Placeholder. x-init.


<div x-data="todos()" x-init="fetchTodos()">
  <!-- ... -->
</div>

<script>
  function todos() {
    return {
      // ...
      todos: [],
      fetchTodos: function () {
        fetch('https://jsonplaceholder.typicode.com/todos')
          .then((response) => response.json())
          .then((data) => {
            this.todos = data.slice(0, 10);
          });
      },
    };
  }
</script>

x-init DOM ( created Vue). – , ( mounted).
, ?_limit=10, query , , .


. Alpine.js. . , . , , .


sandbox. , , .


PS For English speakers I also want to advise a "almost completely free" screencast from the creator of Alpine.js. He is so good that even a link is a pity to share. Well then . In it, the author talks about how to create such a framework as Alpine, and that it is not at all as difficult as it might seem.

All Articles