Сделал небольшой редактор изображений для изучения возможностей vuex с состояниями.
Никто не хочет в рамках инспекции кода высказать свои замечания к написанному?
Файл components/Main.vue
<template>
<div class="Main">
<div class="buttons_bar">
<button v-on:click="setPointerMode" type="button" class="btn btn-light">Point tool</button>
<button v-on:click="setLineMode" type="button" class="btn btn-light">Line tool</button>
<button v-on:click="setCircleMode" type="button" class="btn btn-light">Circle tool</button>
<button v-on:click="setRectangleMode" type="button" class="btn btn-light">Rectangle tool</button>
<button v-on:click="destroy" type="button" class="btn btn-light">Clear tool</button>
</div>
<div>
<canvas id="cnv" height="300" width="600" v-on:mousemove="coord" v-on:click="canvas_left_click"></canvas>
</div>
<div id="status_bar">
<div>Mode: {{ $store.state.currentMode }}</div>
<div>X: {{ $store.state.cursor.X }}</div>
<div>Y: {{ $store.state.cursor.Y }}</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
name: "Main",
methods: mapActions([
'coord',
'canvas_left_click',
'setPointerMode',
'setLineMode',
'setCircleMode',
'setRectangleMode',
'destroy',
])
};
</script>
<style scoped>
.buttons_bar {
border: 1px solid black;
padding: 5px;
}
div > canvas {
width: 600px;
height: 300px;
border: 1px solid red;
}
</style>
Файл store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const ModeEnum = Object.freeze({
"PointerTool": "Pointer",
"LineTool": "Line (click canvas to choose start point)",
"LineToolStartPoint": "Line (click canvas to choose finish point)",
"CircleTool": "Circle (click canvas to choose center)",
"CircleToolCenterPoint": "Circle (choose radius)",
"RectangleTool": "Rectangle (click canvas to set top left corner)",
"RectangleToolTopLeftCorner": "Rectangle (click canvas to set bottom right corner)",
});
const state = {
cursor: {
X: 0,
Y: 0,
},
temporaryPoint: {
X: 0,
Y: 0,
},
currentMode: ModeEnum.PointerTool,
}
const mutations = {
coord(state, pos) {
state.cursor.X = pos.X;
state.cursor.Y = pos.Y;
},
setMode(state, mode) {
state.currentMode = mode;
},
savePointCoordinates(state, pos) {
state.temporaryPoint.X = pos.X;
state.temporaryPoint.Y = pos.Y;
},
drawLine(state, pos) {
var canvas = document.getElementById("cnv");
var context = canvas.getContext("2d");
context.beginPath();
context.moveTo(state.temporaryPoint.X, state.temporaryPoint.Y);
context.lineTo(pos.X, pos.Y);
context.stroke();
},
drawCircle(state, pos) {
var canvas = document.getElementById("cnv");
var context = canvas.getContext("2d");
context.beginPath();
var radius = Math.sqrt((state.temporaryPoint.X - pos.X) * (state.temporaryPoint.X - pos.X) + (state.temporaryPoint.Y - pos.Y) * (state.temporaryPoint.Y - pos.Y));
context.arc(state.temporaryPoint.X, state.temporaryPoint.Y, radius, 0, Math.PI * 2, false);
context.strokeStyle = "red";
context.stroke();
},
drawRectangle(state, pos) {
var canvas = document.getElementById("cnv");
var context = canvas.getContext("2d");
context.beginPath();
context.rect(state.temporaryPoint.X, state.temporaryPoint.Y, pos.X, pos.Y);
context.stroke();
},
}
const actions = {
coord({
commit
}, event) {
var canvas = document.getElementById("cnv");
var rect = canvas.getBoundingClientRect();
var pos = {
X: event.clientX - rect.left,
Y: event.clientY - rect.top,
};
commit('coord', pos);
},
setPointerMode: ({
commit
}) => commit('setMode', ModeEnum.PointerTool),
setLineMode: ({
commit
}) => commit('setMode', ModeEnum.LineTool),
setCircleMode: ({
commit
}) => commit('setMode', ModeEnum.CircleTool),
setRectangleMode: ({
commit
}) => commit('setMode', ModeEnum.RectangleTool),
canvas_left_click({
commit
}, event) {
var canvas = document.getElementById("cnv");
var rect = canvas.getBoundingClientRect();
var pos = {
X: event.clientX - rect.left,
Y: event.clientY - rect.top,
};
switch (state.currentMode) {
case ModeEnum.PointerTool:
console.log('Current state is: ' + state.currentMode);
break;
case ModeEnum.LineTool:
commit('savePointCoordinates', pos);
commit('setMode', ModeEnum.LineToolStartPoint);
break;
case ModeEnum.LineToolStartPoint:
commit('drawLine', pos);
commit('setMode', ModeEnum.LineTool);
break;
case ModeEnum.CircleTool:
commit('savePointCoordinates', pos);
commit('setMode', ModeEnum.CircleToolCenterPoint);
break;
case ModeEnum.CircleToolCenterPoint:
commit('drawCircle', pos);
commit('setMode', ModeEnum.CircleTool);
break;
case ModeEnum.RectangleTool:
commit('savePointCoordinates', pos);
commit('setMode', ModeEnum.RectangleToolTopLeftCorner);
break;
case ModeEnum.RectangleToolTopLeftCorner:
commit('drawRectangle', pos);
commit('setMode', ModeEnum.RectangleTool);
break;
default:
break;
}
},
destroy() {
var main = document.getElementById("cnv");
main.ctx = main.getContext("2d");
main.ctx.clearRect(0, 0, 600, 300);
},
}
const getters = {}
export default new Vuex.Store({
state,
getters,
actions,
mutations
})
Мои собственные заметки:
Store предназначен только для хранения данных, которые нужны нескольким компонентам. Все, что касается только лишь одного компонента, должно находиться в компонента. Т.е., все методы, которые касаются отрисовки, я бы перенес непосредственно в компонент. Context, соответственно тоже может храниться в компоненте, и тогда не будет необходимости получать его каждый раз. Actions - предназначены для асинхронной работы с хранилищем. Те методы, которые используются у Вас в actions этому не соответствуют. Поэтому я бы их тоже перенес в компонент.
Хотя... при работе с canvas, огромные функции, которые управляют холстом я выношу в отдельные файлы и просто импортирую их в компонент.
Что касается моделуй в Store, то у меня это выглядит так:
файл modules/index.js
import person from './person';
import preview from './preview';
import grid from './grid';
import header from './header';
import bigData from './bigData';
import loading from './loading';
export default {
person,
preview,
grid,
header,
bigData,
loading,
};
файл index.js
import Vue from 'vue';
import Vuex from 'vuex';
import modules from './modules';
Vue.use(Vuex);
const store = new Vuex.Store({
modules,
});
export default store;
как пример, modules/loading.js Модуль отвечает за отображание лоадера при запросах на сервер.
const loading = {
state: {
isLoading: false,
},
mutations: {
SHOW_LOADING: state => {
state.isLoading = true;
},
HIDE_LOADING: state => {
state.isLoading = false;
},
},
};
export default loading;
Но Vue очень гибок, и все что я сказал - это только лишь моя практика. Каждый может делать так, как ему будет удобно.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Какие существуют виды рекламных бордов и как выбрать подходящий?
Скорее всего скрипт, но как понимаю, есть варианты с использованием обращений к БД, либо без негоХотелось бы конечно без, но в чем плюсы с БД и различия...
На данный вопрос уже ответили: