I'm a beginner in VueJS. And as part of my learning process, I'm building a knob for my Pomodoro app. This is my fiddle.
I copied the knob code from codepen, which is implemented using jquery. As you can see in the fiddle most of the job is done by jquery.
I need to try and do this using Vue.js, using its methods and states.
How to refactor this code to a better Vue.JS code? Any suggestions much appreciated.
Vue.component('timer', {
mounted() {
var knob = $('.knob');
var angle = 0;
var minangle = 0;
var maxangle = 270;
var xDirection = "";
var yDirection = "";
var oldX = 0;
var oldY = 0;
function moveKnob(direction) {
if(direction == 'up') {
if((angle + 2) <= maxangle) {
angle = angle + 2;
setAngle();
}
}
else if(direction == 'down') {
if((angle - 2) >= minangle) {
angle = angle - 2;
setAngle();
}
}
}
function setAngle() {
// rotate knob
knob.css({
'-moz-transform':'rotate('+angle+'deg)',
'-webkit-transform':'rotate('+angle+'deg)',
'-o-transform':'rotate('+angle+'deg)',
'-ms-transform':'rotate('+angle+'deg)',
'transform':'rotate('+angle+'deg)'
});
// highlight ticks
var activeTicks = (Math.round(angle / 10) + 1);
$('.tick').removeClass('activetick');
$('.tick').slice(0,activeTicks).addClass('activetick');
// update % value in text
var pc = Math.round((angle/270)*100);
$('.current-value').text(pc+'%');
}
var RAD2DEG = 180 / Math.PI;
knob.centerX = knob.offset().left + knob.width()/2;
knob.centerY = knob.offset().top + knob.height()/2;
var offset, dragging=false;
knob.mousedown(function(e) {
dragging = true;
offset = Math.atan2(knob.centerY - e.pageY, e.pageX - knob.centerX);
})
$(document).mouseup(function() {
dragging = false
})
$(document).mousemove(function(e) {
if (dragging) {
if (oldX < e.pageX) {
xDirection = "right";
} else {
xDirection = "left";
}
oldX = e.pageX;
if(xDirection === "left") {
moveKnob('down');
} else {
moveKnob('up');
}
return false;
}
})
}
});
This example runs without jQuery.
https://jsfiddle.net/guanzo/d6vashmu/6/
Declare all the variables you need in the data function.
Declare all functions under the methods property.
Declare variables that are derived from other variables in the computed property, such as knobStyle, activeTicks, and currentValue, which are all computed from angle. Whenever angle changes, these 3 computed properties will automatically update.
Regarding the general usage of Vue, you should focus on manipulating the data, and letting Vue update the DOM for you.
Related
Im executing this code inside vue created() method:
const width = window.innerWidth;
const columns = this.columns.slice()
let colVis = columns.map((element) => {
if(element.sClass == 'min-tv' && width < 2500) {
element.visible = false;
return element;
} else if(element.sClass == 'min-desktop-lg' && width < 1980) {
element.visible = false;
return element;
} else {
return element;
}
});
console.log(columns);
console.log(colVis);
For some reason both arrays returns same values (and this.columns too).
Everything is wraped inside Proxy - arrays and their values.
I cant understand whats going on and why i can't have clone of array?
I don't use computed, because it's initialization values (for Datatables colvis).
You should use filter to filter data from an array.
const width = window.innerWidth;
const columns = this.columns.slice()
let colVis = columns.map((element) => {
if(element.sClass == 'min-tv' && width < 2500) {
element.visible = false;
return element;
} else if(element.sClass == 'min-desktop-lg' && width < 1980) {
element.visible = false;
return element;
} else {
return element;
}
}).filter((element) => element.visible);
console.log(columns);
console.log(colVis);
It turns out to be vue bug.
Using inline window.innerWidth breaks its normal behavior.
I’m new to both Ionic and Vue.js. I’m taking advantage of this summer break to start learning both.
I’m building a mobile app for this purpose and so far, so good. However, I have found and issue that I hope you could help me with. Namely, how to fetch or “call” data from one file to another (Is it called routing?).
In my app, I am trying to start/open a function named myFunction() from one of the pages (quiz.vue) when I call it using v-on:click="myFunction3".
This function is located in a JS file called quizz.js, and it is located in the assets folder. This is its path: (“./assets/js/quizz.js”).
I have tried many things to make it work and finally it is working as it should. However, I think my solution is not optimal as it keeps throwing “Uncaught TypeErrors” in the console of the Developer’s Tool…even though it works.
My solution was to push the function inside methods: this.$router.push(myFunction3())
Also, when running the app, it says that myFunction() , and other functions in the same quizz.js file, “is define but never used”.
If you could advise me with anything, I would be most grateful. I am still a beginner so please explain it to me in as simple a manner as possible.
methods:{
openMenu(){
menuController.open("app-menu")
},
myFunction3(){
this.$router.push(myFunction3())
},
Below, the quizz.js file:
var mlhttp = new XMLHttpRequest();
mlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
const quiz = myObj.results[0]['question'];
const correctAnswer = myObj.results[0]['correct_answer'];
const incorrect = myObj.results[0]['incorrect_answers'];
incorrect.push(correctAnswer);
shuffle(incorrect);
document.getElementById("ans").innerHTML = quiz;
var text = "";
var val = 0;
var i;
for (i = 0; i < incorrect.length; i++) {
if(incorrect[i] == correctAnswer){
text += "<ion-button fill='outline' id='right' onClick='increment();myFunc();'/><b>" + incorrect[i] + "</b></ion-button></br>";
val = val + 1;
}else{
text += "<ion-button fill='outline' class='wrong' onClick='myFunc2();'/><b>" + incorrect[i] + "</b></ion-button></br>";
}
}
document.getElementById("ans5").innerHTML = text;
}
};
var j=0;
function myFunction3() {
document.getElementById("ans6").innerHTML = "";
mlhttp.open("GET", "https://opentdb.com/api.php?amount=1", true);
mlhttp.send();
j++;
document.getElementById('ans11').innerHTML=j;
}
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
function myFunc(){
document.getElementById("ans6").innerHTML = "<h1 style='color:green'><i class='fa fa-check'></i> That is correct!</h1>";
document.getElementById("right").style.color = "white";
document.getElementById("right").style.backgroundColor = "green";
var audio = new Audio('./assets/sound/win.mp3');
audio.play();
}
function myFunc2(){
document.getElementById("ans6").innerHTML = "<h1 style='color:red'><i class='fa fa-thumbs-down' ></i>Wrong Answer! </h1>";
document.getElementById("right").style.color = "white";
document.getElementById("right").style.backgroundColor = "green";
var x = document.getElementsByClassName("wrong");
var i;
for (i = 0; i < x.length; i++) {
x[i].style.backgroundColor = "rgba(255, 0, 0, 0.8)";
x[i].style.color = "white";
}
//document.getElementById("wrong").style.color = "red";
var audio = new Audio('./assets/sound/wrong.mp3');
audio.play();
}
var i=0;
function increment() {
i++;
document.getElementById('ans10').innerHTML=i;
}
I'm making a game where the player must avoid random falling objects. I dont know how to implement pausing. I've been stuck on this for 2 days!
I tried using gotoAndPlay and such, but the objects continue to run in the background. When I resume the game, they're still falling and it seems like the frame resets and loads new random falling objects.
var steps:Number = 10;
var spriteX:Number = 280;
var spriteY:Number = 650;
var alienCounter=1;
var asteroidCounter=1;
var live:Number=3;
var depthLevel=3000;
var score:Number = 0;
var gamePaused;
dropTimer=setInterval(createAlien,2000);
drpTimer2=setInterval(createAsteroid,1000);
//---- functions ----
function checkKeys()
{
if (Key.isDown(Key.RIGHT))
{
spriteX += steps;
}
else if (Key.isDown(Key.LEFT))
{
spriteX -= steps;
}
}
function updateSpaceship()
{
ship._x = spriteX;
ship._y = spriteY;
}
function createAlien()
{
var curr_alien;
curr_alien=attachMovie("alien","alien"+alienCounter,depthLevel);
curr_alien._y=40;
curr_alien._x=Math.random()*510+20;
curr_alien._xscale=curr_alien._yscale=50;
curr_alien.speed=Math.random()*10+3;
alienCounter+=1;
depthLevel+=1;
curr_alien.onEnterFrame=alienMove;
}
function alienMove()
{
if(!gamePaused)
{
this._y+=this.speed;
if(this.hitTest(ship))
{
score += 1;
trace(score);
removeMovieClip(this);
}
}
}
function createAsteroid()
{
var curr_asteroid;
curr_asteroid=attachMovie("asteroid","asteroid"+asteroidCounter,depthLevel);
curr_asteroid._y=40;
curr_asteroid._x=Math.random()*510+20;
curr_asteroid._xscale=curr_asteroid._yscale=50;
curr_asteroid.speed=Math.random()*10+3;
asteroidCounter+=1;
depthLevel+=1;
curr_asteroid.onEnterFrame=asteroidMove;
}
function asteroidMove()
{
if(!gamePaused)
{
this._y+=this.speed;
if(this.hitTest(ship))
{
live -= 1;
trace(live);
removeMovieClip(this);
if(live<=0)
{
gotoAndPlay(5);
}
}
}
}
this.onEnterFrame = function()
{
checkKeys();
updateSpaceship();
if(Key.isDown(80))
{
if(!gamePaused)
{
gamePaused=true;
gotoAndPlay(4);
}
else
{
gamePaused=false;
gotoAndStop(3);
}
}
};
i decided to use a key instead because i cannot find any solutions when trying to use a button. The pause function is not working as i expected, i need to enter key 'p' several times to pause it, but i dont want the frame resets and loads more random objects when i resume it.
try this:
remove your:
this.onEnterFrame = function()
{
checkKeys();
updateSpaceship();
if(Key.getCode() == 80)
{
if(!gamePaused)
{
gamePaused=true;
gotoAndPlay(4);
trace("AAA")
}
else
{
gamePaused=false;
gotoAndStop(3);
trace("BBB")
}
}
};
Add this (pause by pressing the 'P' key on your keyboard):
var keyListener:Object = new Object();
keyListener.onKeyUp = function() {
if(Key.getCode() == 80) {
gamePaused = !gamePaused;
mainLoop();
}
};
Key.addListener(keyListener);
function mainLoop() {
if (gamePaused) {
gotoAndStop(4); // update game actions here
trace("game is paused");
return;
}
gotoAndStop(3); // update game actions here
trace("game is running");
}
Alternatively if you need to pause using a button:
my_pause_Button.onRelease = function() { // your button instance name 'my_pause_Button'
gamePaused = !gamePaused;
mainLoop();
};
Put this in your button function or keydown function:
stage.frameRate = 0.01;
I think that, bydefault renderer always refer to its calling object as scope. and we do not have to define anything but in my grid i have different behaviour.
I have to define rendere function runtime.
I make column object and for each column i assign renderer.
for (var i = 0; i < columns.length; i++) {
newRenderer = function (v, m, r, rI, cI, s)
{
if(this.originalRend) <<<<<-----------------
// "this" is not object of column but whole page.
{
//then call original}
else {
// call new renderer
}
}
columns[i].originalRend = columns[i].renderer;
columns[i].renderer = newRenderer;
}
In my newRenderer function "THIS" does not refer to column object. WHY?????
and how to do that????
You should be able to use scope as a config option of the column, and that will be used by the renderer:
{
renderer: function(val){
return val.trim();
},
scope: this
}
Or, in the case of your code:
for (var i = 0; i < columns.length; i++) {
newRenderer = function (v, m, r, rI, cI, s)
{
if(this.originalRend) <<<<<-----------------
// "this" is not object of column but whole page.
{
//then call original}
else {
// call new renderer
}
}
//THIS LINE ADDED:
columns[i].scope = columns[i];
columns[i].originalRend = columns[i].renderer;
columns[i].renderer = newRenderer;
}
See docs here: http://docs.sencha.com/extjs/4.1.3/#!/api/Ext.grid.column.Column-cfg-scope
Scope does not work as column or this.
The best way is to overrite prepareData method of header container.
Ext.override(Ext.grid.header.Container, {
prepareData: function(data, rowIdx, record, view, panel) {
//console.log("we r in prepare Data");
var me = this,
obj = {},
headers = me.gridDataColumns || me.getGridColumns(),
headersLn = headers.length,
dirtyCls = me.dirtyCls,
colIdx = 0,
header,
headerId,
renderer,
value,
metaData,
store = panel.store;
for (; colIdx < headersLn; colIdx++) {
metaData = {
tdCls: '',
style: ''
};
header = headers[colIdx];
headerId = header.id;
renderer = header.renderer;
value = data[header.dataIndex];
if (typeof renderer == "function") {
value = renderer.call(
//--------change made below.------------------
header.scope || header || me.ownerCt,
//----------------end-------------------------
value,
// metadata per cell passing an obj by reference so that
// it can be manipulated inside the renderer
metaData,
record,
rowIdx,
colIdx,
store,
view
);
}
// <debug>
if (metaData.css) {
// This warning attribute is used by the compat layer
obj.cssWarning = true;
metaData.tdCls = metaData.css;
delete metaData.css;
}
// </debug>
if (me.markDirty) {
obj[headerId + '-modified'] = record.isModified(header.dataIndex) ? dirtyCls : '';
}
obj[headerId+'-tdCls'] = metaData.tdCls;
obj[headerId+'-tdAttr'] = metaData.tdAttr;
obj[headerId+'-style'] = metaData.style;
if (typeof value === 'undefined' || value === null || value === '') {
value = header.emptyCellText;
}
obj[headerId] = value;
}
return obj;
},
}
I'm looking for a thumbnail tiles scroller/slideshow/slider
Here is the example http://safari.to/clients
Really appreciate if anyone could help :) Thanks
When you see something on any website, its easy to inspect and see how they are doing it.
The website mentioned by you is doing it using their own script instead of a plug in
See the following code from http://safari.to/assets/js/script.js. You will also need to see how they are styling the sliders by inspecting their CSS code
// Agencies slide
var clients = Math.floor(Math.random() * 2) + 1; // nth-child indices start at 1
if ( clients == 1){
$('.agencies.clients').hide();
}
else
{
$('.brands.clients').hide();
}
$('.agencies menu a').bind({
click: function()
{
if(sliding) return false;
var pointer = $(this);
var width = $('.agencies .scroller li').length * 137;
var current = parseInt($('.agencies .scroller').css('left'));
var distance = 0;
if(pointer.is('.right-pointer'))
{
if(current == -1920) distance = current - 137;
else distance = current - 960;
if((width + current) < 960)
distance = current;
}
else
{
distance = current + 1097;
if(distance > 0)
distance = 0;
}
sliding = true;
$('.scroller').animate({
left: distance + 'px'
}, 300,
function()
{
sliding = false;
});
}
});