Есть тут люди которые писали на ангуляре 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:16. |