Есть тут люди которые писали на ангуляре 2 и vue? что скажите?
П.с я понимаю что на vue можно лепить архитектуру как хочешь, а ангуляр уже навязывает свою. |
Цитата:
Цитата:
Панику оставьте для Ангуляров, Реактов и т.п.) Цитата:
Цитата:
|
nerv_,
Верстка тут вообще не причем. Я про композицию UI и архитектуру в целом. То есть каждый компонент это своя папка. В ней лежит шаблон, класс и стили. Это то, к чему мы пришли с ангуляр2. |
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_,
Но ведь приложение это и будет дерево компонентов... |
kobezzza, что делает деректива wait?)
|
Цитата:
|
kobezzza, сенк, подумал не много о другом)
|
Законно ли вызывать методы дочерних компонентов через $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> |
Да, по сути это не дочерние компоненты, а компоненты-свойства, т.е. у нас композиция.
|
Это радует, ибо предложенный вариант модального окна в доке, вообще не впечатляет.
Когда одно "модальное окно", тогда еще ладно, но если их несколько, то под каждый объявлять свойство не очень.. |
Если объектов много, то лучше юзать события и Vuex.
|
Да я только разбираюсь во всем этом, но 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(); } }, }, }; Надеюсь после просмотра этого кода, никому плохо не станет ;) |
Тогда в принципе, всё верно.
|
Может у кого-то в закладках пылятся годный материал, никто не хочет поделиться? :)
|
Цитата:
Лучше вместо той колбасы, которую ты колбасишь, внимательнее посмотри на пример. То, что ты написал абсолютно не нужно. |
nerv_, да вроде все видел, возможно я и усложняю, но хочется чистоты в компонентах.
мне бросилось в глаза свойство showModal, которое управляет компонентом modal и не является его частью, хотелось бы его положить внутрь компонента modal. (хотя может это и глупо). Попробую переварить эту лашпу, может все на самом деле проше. |
nerv_,
Получилось вот такая хрень. Все круто, но не слишком ли много логики выносится из компонента?? И печалька получится, если использовать два диалога. Либо я что-то не понимаю, либо без callback тут не обойтись. https://jsfiddle.net/s63c8djs/ |
Цитата:
|
nerv_, например так. http://javascript.ru/forum/offtopic/...tml#post430983
|
Lemme, делай так, как считаешь правильным :) Время тебя рассудит)
|
|
Я так понимаю что бы писать компоненты на 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) } } |
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 аннотаций. |
Гик изучает апи 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> |
Цитата:
|
Цитата:
|
Цитата:
foo: String = '1'; На @prop({type: String, default: '1'}) foo; А дальше главный декоратор model, которым врапится компонент, создаёт экземпляр класса и на его основе делает Vue.component. Конструктор базового класса возвращает объект, где геттеры/сеттеры заменены на компьютеды, поля с декораторыми @prop и @field на props и data(). Методы вставляются в methods, а зарезирвированные слова типа mounted как есть. Также статики становятся свойствами $options Vue. В общем всё довольно просто и главное, что работает автокомплит и super. Еще я для сеттеров и геттеров генерю методы, например fooGetter, чтобы можно было вызывать их через super. |
kobezzza, ты написал свой транслятор?
|
Цитата:
Если в коде есть участки шаблонного повторения кода и нет возможности силами языке это как то убрать или сделать красиво - макросы идеальное решение. Почитай про предметно-ориентированное программирование :) http://jetbrains.ru/products/mps/ |
Часовой пояс GMT +3, время: 07:19. |