Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   Vue' thread 1 (https://javascript.ru/forum/offtopic/58273-vue%27-thread-1-a.html)

cyber 03.09.2016 06:30

Есть тут люди которые писали на ангуляре 2 и vue? что скажите?
П.с я понимаю что на vue можно лепить архитектуру как хочешь, а ангуляр уже навязывает свою.

nerv_ 03.09.2016 08:01

Цитата:

Сообщение от destus
А зачем вообще что-то изобретать, когда есть БЭМ?

ты о чем вообще? ИЛи я не знаю БЕЭ или БЭМ о том, как верстать HTML/CSS. Если под этим ты имел ввиду композицию UI, то у Vue для этих целей предусмотрены директивы и компоненты.

Цитата:

Сообщение от cyber
просто он нативно вставлен в файл компонента, и хранить его рядом в файле и делать импорт не получится вроде.

Вроде получится. Я так делаю. Предлагаю вместо паники и голословных заявлений начать с Hello World
Панику оставьте для Ангуляров, Реактов и т.п.)

Цитата:

Сообщение от cyber
получится на vuе сделать что то такое через декоратор?

получится и без декоратора

Цитата:

Сообщение от cyber
Есть тут люди которые писали на ангуляре 2 и vue? что скажите?

уже сказали. Ты тему читал? Или чукча не читатель, чукча писатель? :)

destus 03.09.2016 09:10

nerv_,
Верстка тут вообще не причем. Я про композицию UI и архитектуру в целом. То есть каждый компонент это своя папка. В ней лежит шаблон, класс и стили. Это то, к чему мы пришли с ангуляр2.

kobezzza 03.09.2016 10:18

Cyber, заюззай вебпак и все.

Вот пример моего компонента на Vue.

'use strict';

/*!
 * TravelChat Client
 * Released under the FSFUL license
 */

import iData from '../i-data/i-data';
import keyCodes from '../../core/keyCodes';
import * as tpls from './b-button.ss';
import { model } from '../../core/block';
import { wait } from '../i-block/i-block';

@model(tpls)
export default class bButton extends iData {
	/**
	 * Button type
	 */
	type: string = 'button';

	/**
	 * Connected form id
	 */
	form: ?string;

	/**
	 * Icon before text
	 */
	preIcon: ?string;

	/**
	 * Icon after text
	 */
	icon: ?string;

	/**
	 * Tooltip text
	 */
	hint: ?string;

	/**
	 * Tooltip position
	 */
	hintPos: ?string;

	/** @override */
	static mods = {
		rounding: [
			'none',
			['small'],
			'normal',
			'big'
		],

		width: [
			['normal'],
			'full'
		],

		opened: [
			'true',
			['false']
		]
	};

	/**
	 * Opens the dropdown
	 */
	@wait('loading')
	open() {
		if (this.$slots.dropdown && this.setMod('opened', true)) {
			this.emit('open');
		}
	}

	/**
	 * Closes the dropdown
	 */
	@wait('loading')
	close() {
		if (this.$slots.dropdown && this.setMod('opened', false)) {
			this.emit('close');
		}
	}

	/**
	 * Toggles the dropdown
	 */
	toggle() {
		this.ifSomeMod(['opened'], true) ? this.close() : this.open();
	}
}

nerv_ 04.09.2016 09:07

Цитата:

Сообщение от destus
Я про композицию UI и архитектуру в целом. То есть каждый компонент это своя папка.

Мне кажется ты путаешь архитектуру приложения со структурой каталогов (приложения/модуля/компонента).

destus 04.09.2016 10:17

nerv_,
Но ведь приложение это и будет дерево компонентов...

cyber 05.09.2016 09:05

kobezzza, что делает деректива wait?)

kobezzza 05.09.2016 10:17

Цитата:

Сообщение от cyber (Сообщение 427695)
kobezzza, что делает деректива wait?)

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

cyber 05.09.2016 11:00

kobezzza, сенк, подумал не много о другом)

Lemme 07.10.2016 17:27

Законно ли вызывать методы дочерних компонентов через $ref?

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <my-component ref="myComponent"></my-component>
    <button @click="handleToggle">toggle</button>
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.1/vue.min.js"></script>
  <script>
    Vue.component('my-component', {
      template: '<div v-if="active">my-component</div>',
      data: () => ({ active: false }),
      methods: {
        toggle() {
          this.active = !this.active
        }
      }
    })

    new Vue({
      el: '#app',
      methods: {
        handleToggle() {
          this.$refs.myComponent.toggle() // я об этом
        }
      }
    })
  </script>
</body>
</html>

kobezzza 07.10.2016 18:31

Да, по сути это не дочерние компоненты, а компоненты-свойства, т.е. у нас композиция.

Lemme 07.10.2016 18:49

Это радует, ибо предложенный вариант модального окна в доке, вообще не впечатляет.

Когда одно "модальное окно", тогда еще ладно, но если их несколько, то под каждый объявлять свойство не очень..

kobezzza 07.10.2016 20:02

Если объектов много, то лучше юзать события и Vuex.

Lemme 07.10.2016 20:34

Да я только разбираюсь во всем этом, но vuex юзаю. Но только для тех событий, которые влияют на приложение.

Вот action удаления статьи (пишу простенький блог).

async removeArticle({ commit }, id) {
    commit(REMOVE_ARTICLE_REQUEST);

    try {
      await axios.delete(`/api/articles/${id}`);
      commit(REMOVE_ARTICLE_SUCCESS, id);
    } catch (e) {
      commit(REMOVE_ARTICLE_FAILURE, e.response.data.message);
    }
  }


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

Я смотрю в сторону событий, но, какой-то слишком запутанный получается "банальный диалог", цель которого запустить callback и скрыть себя.

export default {
  props: {
    onConfirm: Function,
    onCancel: Function,
  },
  data: () => ({ active: false }),
  methods: {
    open() {
      this.active = true;
    },
    close() {
      this.active = false;
    },
    confirmHandler() {
      this.close();

      if (this.onConfirm) {
        this.onConfirm();
      }
    },
    cancelHandler() {
      this.close();

      if (this.onCancel) {
        this.onCancel();
      }
    },
  },
};


Надеюсь после просмотра этого кода, никому плохо не станет ;)

kobezzza 07.10.2016 20:37

Тогда в принципе, всё верно.

Lemme 07.10.2016 20:59

Может у кого-то в закладках пылятся годный материал, никто не хочет поделиться? :)

nerv_ 07.10.2016 22:35

Цитата:

Сообщение от Lemme
ибо предложенный вариант модального окна в доке, вообще не впечатляет

Не впечатляет тем, что слишком простой, а ты намеренно хочешь усложнить?)))
Лучше вместо той колбасы, которую ты колбасишь, внимательнее посмотри на пример. То, что ты написал абсолютно не нужно.

Lemme 07.10.2016 22:54

nerv_, да вроде все видел, возможно я и усложняю, но хочется чистоты в компонентах.

мне бросилось в глаза свойство showModal, которое управляет компонентом modal и не является его частью, хотелось бы его положить внутрь компонента modal. (хотя может это и глупо).

Попробую переварить эту лашпу, может все на самом деле проше.

Lemme 08.10.2016 00:04

nerv_,
Получилось вот такая хрень. Все круто, но не слишком ли много логики выносится из компонента??
И печалька получится, если использовать два диалога. Либо я что-то не понимаю, либо без callback тут не обойтись.

https://jsfiddle.net/s63c8djs/

nerv_ 08.10.2016 18:03

Цитата:

Сообщение от Lemme
Все круто, но не слишком ли много логики выносится из компонента??

Ты про один флаг? Даже не знаю что тебе на это ответить... И как ты собрался управлять видимостью окна без этого флага, тоже не знаю...

Lemme 08.10.2016 19:37

nerv_, например так. http://javascript.ru/forum/offtopic/...tml#post430983

nerv_ 12.10.2016 09:11

Lemme, делай так, как считаешь правильным :) Время тебя рассудит)

nerv_ 21.10.2016 08:04

Почему разработчики GitLab используют Vue.js?

cyber 21.10.2016 17:24

Я так понимаю что бы писать компоненты на es6 через классы, то нужно делать что то такое? (т.е юзать либу vue-class-component)

import Component from 'vue-class-component'

@Component({
  props: {
    propMessage: String
  },
  template: `
    <div>
      <input v-model="msg">
      <p>prop: {{propMessage}}</p>
      <p>msg: {{msg}}</p>
      <p>computed msg: {{computedMsg}}</p>
      <button @click="greet">Greet</button>
    </div>
  `
})
class App {
  // return initial data
  data () {
    return {
      msg: 123
    }
  }

  // lifecycle hook
  mounted () {
    this.greet()
  }

  // computed
  get computedMsg () {
    return 'computed ' + this.msg
  }

  // method
  greet () {
    alert('greeting: ' + this.msg)
  }
}

kobezzza 21.10.2016 17:56

Cyber, как напишешь - таки будет) Я раньше по похожему делал, но хотелось нормального автокомплита, в итоге сделал так:

import iData from '../i-data/i-data';
import * as tpls from './b-button.ss';
import { PARENT } from '../i-block/i-block';
import { model } from '../../core/block';

@model(tpls)
export default class bButton extends iData {
	/**
	 * Button type
	 */
	type: string = 'button';

	/**
	 * Connected form id
	 */
	form: ?string;

	/**
	 * Input autofocus mode
	 */
	autofocus: ?boolean;

	/**
	 * Icon before text
	 */
	preIcon: ?string;

	/**
	 * Icon after text
	 */
	icon: ?string;

	/**
	 * Tooltip text
	 */
	hint: ?string;

	/**
	 * Tooltip position
	 */
	hintPos: ?string;

	/** @override */
	static mods = {
		rounding: [
			'none',
			['small'],
			'normal',
			'big'
		],

		theme: [
			PARENT,
			'dark',
			'light',
			'icon'
		]
	};

	/* @override */
	created() {
		this.initCloseHelpers();
	}
}


Декоратор матчит класс и генерит компонент, а инфа о типах пропсов берётся из Flow аннотаций.

join 22.10.2016 07:10

Гик изучает апи Vue 3.0 .:yes:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>vue.js & dinamics.js | https://jsfiddle.net/yyx990803/y91wy85p/</title>
	
	<style>
	.draggable-header-view {
	  background: #fff url(http://thumbsnap.com/i/YopxPzbo.jpg?1021) no-repeat 0 0;
	  background-size: 100% auto;
	  width: 320px;
	  height: 427px;
	  overflow: hidden;
	  margin: 30px auto;
	  position: relative;
	  font-family: 'Roboto', Helvetica, Arial, sans-serif;
	  color: #fff;
	  font-size: 14px;
	  font-weight: 300;
	  box-shadow: 0 0 5px 1px rgb(178, 97, 44);
	  -webkit-user-select: none;
	  -moz-user-select: none;
	  -ms-user-select: none;
	  user-select: none;
	}
	.draggable-header-view .bg {
	  position: absolute;
	  top: 0;
	  left: 0;
	  z-index: 0;
	}
	.draggable-header-view .header,
	.draggable-header-view .content {
	  position: relative;
	  z-index: 1;
      padding: 0 10px;
	  box-sizing: border-box;
	}
	.draggable-header-view .header {
	  height: 160px;
	}
	.draggable-header-view .content {
	  color: #fff;
	  line-height: 24px;
	  position: absolute;
	  top:0;
	  left:0;
	  right:0;
	  opacity: 0.2;
	}
	.draggable-header-view .content p{
      font-size: 24px;
      margin: 0;
	  opacity: inherit;
	}
	.draggable-header-view .content p span{
	  font-size: inherit;
	}
	.draggable-header-view svg{
	    cursor: -webkit-grab;
	}
	.draggable-header-view svg:active,
	.draggable-header-view svg:focus{
	    cursor: -webkit-grabbing;
	}
	</style>
	
	<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
	<script src="https://unpkg.com/dynamics.js@1.1.5"></script>
  </head>
  <body>

<!-- template for the component -->
<script type="text/x-template" id="header-view-template">
  <div class="draggable-header-view"
    @mousedown="startDrag" @touchstart="startDrag"
    @mousemove="onDrag" @touchmove="onDrag"
    @mouseup="stopDrag" @touchend="stopDrag" @mouseleave="stopDrag">
    <svg class="bg" width="320" height="460">
	  <path :d="plusPathLeft" fill="#b2612c">Vue.js</path>
	  <path :d="plusPathRight" fill="#b2612c"></path>
    </svg>
    <div class="content" :style="contentPosition">
      <slot name="content"></slot>
    </div>
  </div>
</script>

<div id="app" @touchmove.prevent>
  <draggable-header-view>
    <template slot="content">
      <p>Api <span>V</span><span>u</span><span>e</span><span>.</span><span>j</span><span>s</span> v.3.0</p>
    </template>
  </draggable-header-view>
</div>

<script>
(function(window){
var xuy=110;
Vue.component('draggable-header-view', {
  template: '#header-view-template',
  data: function () {
    return {
      dragging: false,
      c: { x: xuy, y: xuy },
      start: { x: 0, y: 0 }
    }
  },
  computed: {
	plusPathLeft: function(){
	    return 'M'+this.c.x+' '+this.c.y+' h35 v35 h35 v35 h-35 v35 h-35 v-35 h-35 v-35 h35'
	},
	plusPathRight: function(){
	    return 'M'+(this.c.x + 143)+' '+(this.c.y - 60)+' h30 v30 h30 v30 h-30 v30 h-30 v-30 h-30 v-30 h30'
	},
    contentPosition: function () {
      var dy = this.c.y - xuy
      var dampen = dy > 0 ? 2 : 4
      return {
		opacity: (dy/dampen/20)
      }
    }
  },
  methods: {
    startDrag: function (e) {
      e = e.changedTouches ? e.changedTouches[0] : e
      this.dragging = true
      this.start.x = e.pageX
      this.start.y = e.pageY
    },
    onDrag: function (e) {
      e = e.changedTouches ? e.changedTouches[0] : e
      if (this.dragging) {
        this.c.x = xuy + (e.pageX - this.start.x)
        var dy = e.pageY - this.start.y
        var dampen = dy > 0 ? 1.5 : 4
        this.c.y = xuy + dy / dampen
      }
    },
    stopDrag: function () {
      if (this.dragging) {
        this.dragging = false
        dynamics.animate(this.c, {
          x: xuy,
          y: xuy
        }, {
          type: dynamics.spring,
          duration: 1234,
          frequency: 537,
          friction: 200,
          anticipationSize: 120
        })
      }
    }
  }
})

new Vue({ el: '#app' })
})(window);
</script>
  </body>
</html>

cyber 22.10.2016 15:12

Цитата:

Сообщение от kobezzza
Декоратор матчит класс и генерит компонент

а можно по подробней, как он генирирует компонент?)

nerv_ 22.10.2016 21:55

Цитата:

Сообщение от cyber
Я так понимаю что бы писать компоненты на es6 через классы, то нужно делать что то такое? (т.е юзать либу vue-class-component)

Очень похоже на то. Меня тоже раньше на классах клинило :) , на самом деле они там по большому счету не нужны. Представить, что ты описываешь объект, а затем просто передаешь его в функцию --- Vue(descriptor). Иными словами, если ты инкапсулируешь в модули, то модуль будет возвращать descriptor, а не класс.

kobezzza 23.10.2016 13:12

Цитата:

Сообщение от cyber (Сообщение 432606)
а можно по подробней, как он генирирует компонент?)

Ну сперва на этапе трансляции я заменяю:

foo: String = '1';


На

@prop({type: String, default: '1'})
foo;


А дальше главный декоратор model, которым врапится компонент, создаёт экземпляр класса и на его основе делает Vue.component. Конструктор базового класса возвращает объект, где геттеры/сеттеры заменены на компьютеды, поля с декораторыми @prop и @field на props и data(). Методы вставляются в methods, а зарезирвированные слова типа mounted как есть. Также статики становятся свойствами $options Vue. В общем всё довольно просто и главное, что работает автокомплит и super. Еще я для сеттеров и геттеров генерю методы, например fooGetter, чтобы можно было вызывать их через super.

cyber 23.10.2016 14:05

kobezzza, ты написал свой транслятор?

kobezzza 23.10.2016 14:20

Цитата:

Сообщение от cyber (Сообщение 432660)
kobezzza, ты написал свой транслятор?

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

Если в коде есть участки шаблонного повторения кода и нет возможности силами языке это как то убрать или сделать красиво - макросы идеальное решение.

Почитай про предметно-ориентированное программирование :)
http://jetbrains.ru/products/mps/


Часовой пояс GMT +3, время: 07:19.