[JS]Klasy problem z zawieraniem metod i własnosci

0

Witam,
Szukałem po kursach, nie znalazłem porządnego kursu o klasach. Na webmade jest nawet troche wiecej niz na innych, ale oni to chyba ten kod pisali tak bez sprawdzania bo troche błędów jest tam.

Chciałbym stworzyć pewną klase, do której przy tworzeniu obiektu odawał bym 4 parametry (a, b, c ,d). Następnie chciałbym dodać kilka metod (metoda1, metoda2, metoda3). Chciałbym, by w każdej metodzie były dostępne przekazane do konstruktora parametry (a, b, c, d). Nie znam klas dlatego nie potrafie zrobić tak prostej rzeczy.

Próbowałem w kodzie poniżej.

function obiekt(a, b, c, d)
{
this.a = a
this.b = b
this.c = c
this.d = d
this.pokaz=wyswietl()
}

function wyswietl()
{
var dane1 = this.param1
var dane2 = this.param2

document.write(dane2)
alert (dane1);

}


var instancja_obiektu = new obiekt("param1", "param2", "param3", "param4")
instancja_obiektu.pokaz()

Dlaczego wyswietla sie okienko z "undefined" zamiast z zawartoscia przekazanej do konstruktora zmiennej?
Kod jest oparty mniejwięcej na tym z Webmade, czy instrukcja "this.pokaz=wyswietl()" ma w ogóle sens, czy nie mozna po prostu napisać "this.wyswietl=wyswietl()"?

0
tMbRaga napisał(a)

czy instrukcja "this.pokaz=wyswietl()" ma w ogóle sens

tak, pokaz bedzie mialo wartosc zwrocona przez funkcje wyswietl

jesli chcesz zeby pokaz bylo funkcja/metoda to da sie tak:

function wyswietl() {
}
this.pokaz = wyswietl;
var wyswietl = function() {
};
this.pokaz = wyswietl;
this.pokaz = function() {
};
0

Nie zrozumiałeś mnie, albo ja Ciebie (albo to i to). ;)

Moze zacznijmy od poczatku.
Chciałbym zadeklarować klase. W C++ mam instrukcje class. Tutaj jak widze robi sie to tak samo jak deklaracje funkcji.

Czyli:

function moja_klasa()
{

}

W tej klasie chciałbym zawrzeć pewne pola (zmienne), oraz metody ktore by operowały na tych zadeklarowanych zmiennych i nie tylko na tych.

Czyli jak to zrobić?
Robie 2 funkcje i próbuje je ze sobą "połączyć" tworząc klase, bo nie rozumiem jak to jest tutaj.

function moja_klasa()
{
var liczba = 15
}

function wyswietl_wartosc()
{
alert(liczba);
}

// Ale to powyżej nie zadziała, bo zmienna liczba w funkcji/klasie moja_klasa ma zakres lokalny.


W C++ mam:

class moja_klasa
{
private:
int liczba = 15;

public:
void wyswietl_wartosc (){cout << liczba;};
}
0

eeee :-) ja nie wiem czy do konca rozumiem, chodzi Ci o cos takiego:

function MojaKlasa() {
  var liczba = 44; // private
  this.tekst = 'A imie jego '; // public
  this.wyswietlWartosc = function() { // public
    alert(this.tekst + liczba);
  };
  return this;
}
var mojObiekt = new MojaKlasa();
mojObiekt.wyswietlWartosc();
// A imie jego 44
alert(mojObiekt.tekst + mojObiekt.liczba);
// A imie jego undefined
0

Super dokładnie o to mi chodziło, jeszcze wielkie dzieki, ze wyrozniles aspekty private i public. Masz u mnie browara ;).

EDIT:
Jeszcze jedno pytanie.

W CSS kod wyglada tak:

div {position:absolute;
left:30px;
top:30px;
z-index:1}

Chciałbym w zaleznosci od pewnych warunków przypisywać je wybranym obiektom, na przykład div, table, tr itd.
Jak to zapisać w javascript?
Szukałem w google. Javascript position, javascript absolute, ale znalazłem troche nie na temat.

0

CSS:

.moja_klasa {
  /* ... */
}

JS:
element.className = 'moja_klasa';
albo:

element.style.position = 'absolute';
element.style.textAlign = 'center';
element.style.zIndex = '1';

i tak dalej...

0

Super działa, tylko jeszcz jeden problem ;).

Instrukcja wewnatrz metody pewnej klasy nie działa:

setTimeout ("this.send()", 1000)

Co dziwne, jezeli zadeklaruje funkcje wyslij(), poza klasa i odwałam sie do niej:

setTimeout ("wyslij()", 1000)

To działa bezproblemu

0

Trzeba skorzystać z tego, że funkcja setTimeout może zamiast łańcucha znaków przyjąć jako pierwszy argument inną funkcję, którą wywoła po upływie danego czasu.
No i trzeba też trochę się nagimnastykować z przekazaniem this, bo inaczej ta metoda zostanie wywołana bez powiązania z obiektem, do którego należy.

function MyClass() {
  var className = 'MyClass';
  this.description = 'moja klasa';
  this.send = function(x) { 
    alert(className + ' [' + this.description + 
      '] send(' + x + ')');
  };
  this.delayedSend = function(x) { 
    var tmpThis = this;
    setTimeout(function() {
      tmpThis.send(x);
    }, 1000);
  };
  return this;
}
var obj = new MyClass();
obj.send('a');
obj.delayedSend('b');
obj.description = 'zmiana opisu';

[dopisane]

Aha, w setTimeout można przekazać this i argumenty do wywołania metody (chyba 3 i 4 parametr), ale to działa jedynie pod Mozillą, dlatego jest ten dziwoląg z anonimową funkcją, która wywołuje właściwą metodę.

0

Dużo rzeczy sie mozna nauczyć dzieki Tobie Panie/kolego piechnat.
Dziekuje za przykładowy kod. Nawet nie wpadłem na to, że wskaźnik this wewnątrz setTimeout-a wskazywał juz nie na moją klase.
Jeszcze raz dziękuje.

EDIT:
Nie chciałbym znowu zawracać, ale mam podobny problem, tyle że z własną metodą w klasie.

function klasa()
{
 this.generate = function (info) 
 {
  var tabela
  var tmpThis = this 

  while (info[i] != undefined)
   {	
     tabela += "<td onclick =\"tmpThis.onclicked(" + i + ")\"</td>";
     i++
   } 
  };

 this.onclicked = function (i)
 { 
  alert(i);
 }; 
}

Oczywiscie w petli while mimo zastosowania wskaźnika this zadeklarowanego w zmiennej w miejscu gdzie wskazywał on na prawidłową klase przykład nie działa.
O sensie kodu powyżej nie ma co dyskutować, to jest tylko przykład napisany, by nie kopiować mojego kodu, a już jest dość obszerny ^^.

Jak dostać sie w zdarzeniu onclick w td, do mojej metody zadeklarowanej w klasie?

0

Oczywiscie w petli while mimo zastosowania wskaźnika this zadeklarowanego w zmiennej w miejscu gdzie wskazywał on na prawidłową klase przykład nie działa.

Zacząć trzeba od tego, że nie powinno się budować dynamicznej treści html ze stringów. Trzeba korzystać z funkcji DOM. Poza tym kolejne elementy tablicy info trzeba przypisać do czegoś stałego. Najlepiej do elementu td. W przeciwnym wypadku info[i] będzie zawsze wskazywać na ostatni element tablicy.

Jak dostać sie w zdarzeniu onclick w td, do mojej metody zadeklarowanej w klasie?

Nie rozumiem tylko czy zmienna this w tej metodzie ma wskazywać na instancje klasy, do której należy czy na element htmla td? Zakładam, że to pierwsze.

<script>
  function Klasa() {
    this.str = 'opis ';
    this.generate = function(info) {
      var myTable = document.getElementById('my_table');
      myTable.border = 1;
      myTable.cellPadding = 5;
      var firstTr = myTable.getElementsByTagName('tr')[0];
      var i = 0, tmpThis = this;
      while (info[i] != undefined) {
        var td = document.createElement('td');
        td.style.cursor = 'pointer';
        td.innerHTML = 'kolumna ' + (i + 1);
        td._info = info[i];
        td.onclick = function() {
          tmpThis.onclicked(this._info);
        }; 
        firstTr.appendChild(td);
        i++;
      }
    };
    this.onclicked = function(i) {
      alert(this.str + i);
    }; 
    return this;
  }
  window.onload = function() {
    (new Klasa()).generate(['jeden', 'dwa', 'trzy']);
  };
</script>
<table id="my_table">
  <tbody><tr></tr></tbody>
</table>
0

Budowanie html-a ze stringów było bardzo proste, tylko były problemy z innerHTML dla tabel w IE, dlatego cała tabele trzeba było innerHTML-em wstawić do DIV-a.

Nie rozumiem tylko czy zmienna this w tej metodzie ma wskazywać na instancje klasy, do której należy czy na element htmla td? Zakładam, że to pierwsze.

Zmienna this ma wskazywać na klase, tak żeby wywołanie:

tmpThis.onclicked(info[i])

albo jak ja to wczesniej robiłem
tmpThis.onclicked(i)
Przekazywało do funkcji onclicked pewne dane, bądź licznik pętli, na podstawie ktorych tworzono dane, ktore nastepnie były przypisywane do formularza.

Troche czarna magia ten DOM dla mnie.
Głównie jezeli chodzi wyobrażenie sobie tej całej obiektowości.
Nie znam metod typu appendChild, a nigdzie nie moge znaleźć obszernego opisu najlepiej z przykładami. Akurat tutaj wiem co robi appendChild.

Natomiast chciałbym, zeby moja tabela miała składnie:

<tr><td>komorka1</td></tr><tr><td>komorka2</td></tr>...

Prosciej mowiac, zeby była jedna kolumna, a wiersze dokładały sie pod każdym nastepnym.
I tutaj poległem z DOM-em totalnie nie wiem jak sie za to zabrać.
Jesli sie nie myle przydałaby sie metoda insertAfter, ale nie ma takiej tylko mozna ja jakos zrobic z istniejacych 2 innych bytów.

Twój kod co dziwne dla mnie działa pod IE, mimo zastosowania innerHTML dla td.

Natomiast po wstawieniu go i małych modyfikacjach do mojego całościowego kodu coś nie chciało zadziałać pod IE, tylko pod Opera, ale wydaje mi sie, ze to przez nie zastosowanie:

window.onload = function()

Jakbyś znalazł dla mnie jeszcze chwilke dałbyś rade przerobić powyższy kod, tak by zmienić format wyswietlanie tabeli na wyżej wymienony?

0

Budowanie html-a ze stringów było bardzo proste, tylko były problemy z innerHTML dla tabel w IE, dlatego cała tabele trzeba było innerHTML-em wstawić do DIV-a.

No nie wiem, może proste, ale dla mnie nie eleganckie a poza tym trzeba by się nieźle napocić żeby przekazać jakiś obiekt w stringu :-)

Troche czarna magia ten DOM dla mnie.

http://developer.mozilla.org/en/docs/Gecko_DOM_Reference (DOM Element Reference)
Do tabel są też specjalne funkcje DOM ale tych z moich przykładów można używać do wszystkich elementów.

Natomiast chciałbym, zeby moja tabela miała składnie:

Zasada jest prosta, tworzysz dowolny element HTML przez createElement i podczepiasz go do jakiejś gałęzi przez appendChild (itp.). Uchwyt gałęzi pobierasz przez getElementById (itp.) albo korzystasz z poprzednio stworzonego i podczepionego. Struktura tych gałęzi jest drzewiasta :) taka jak w kodzie HTML. Koniec.

Pod spodem przykład stworzenia od zera tabeli z 3 wierszami i 3 komórkami w każdym wierszu.

<html>
<head>
<script>
  onload = function() {
    var table = document.createElement('table');
    /* --- dodatki graficzne --- */
    with (table) { 
      border = 4; cellPadding = 10; cellSpacing = 10;
      style.font = 'normal bold 50px tahoma, sans-serif'; 
      style.backgroundColor = '#f00'; }
    /* --- */
    var tbody = document.createElement('tbody');    
    table.appendChild(tbody);
    for (var i = 0; i < 3; i++) {
      var tr = document.createElement('tr');
      tbody.appendChild(tr);
      for (var j = 0; j < 3; j++) {
        var td = document.createElement('td');
        td._str = ((i * 3) + j) + 1;
        td.appendChild(document.createTextNode(td._str));
        /* albo: td.innerHTML = td._str; */
        /* --- dodatki graficzne --- */
        td.style.cursor = 'pointer';
        td.onclick = function() { alert(this._str) };
        td.onmouseover = function() {
          this.style.backgroundColor = '#ff0' };
        td.onmouseout = function() {
          this.style.backgroundColor = '#f00' };
        /* --- */
        tr.appendChild(td);
      }
    }
    document.body.appendChild(table);
  };
</script>
</head>
<body></body>
</html>
0

OK udało mi sie zrobić tabele taka jak chciałem. Ten DOM jest do zrozumienia, no i jak widze daje duzo wiecej mozliwosci, odwołań i pozniejszej konserwacji kodu.

Tabele stworzyłem, ale chciałem ją usunąć i tu kolejny problem:

function moja_klasa()
{
this.del = function () {
deltab = document.getElementById("moja_tabela");
document.removeChild(deltab);
};

this.generate = function (info) {
var table = document.createElement('table');
var tbody = document.createElement('tbody');   
table.appendChild(tbody);
table.id = 'moja_tabela'
 /* dalsza czesc kodu odpowiedzialna za dodawanie tr i td */
td.onclick = function (){
tmpThis.del()
};
};
}

Jednak na kliknięcie na byle jakim td nie skutkuje usunięciem tabeli.

Co mnie jeszcze niepokoji to wydajność...
Uzywajac innerHTML-a i operując stringami, metody na zdarzenia onmouseout i onmouseover działały płynnie. Tak szybko zmieniało sie podswietlenie.
Tutaj przy wyswietleniu "skacze" jak sie przejedzie myszka.

0
this.del = function () {
deltab = document.getElementById("moja_tabela");
deltab.parentNode.removeChild(deltab); // zamiast document.body
};

Dlaczego nie document.body.removeChild() ? Bo ta tabelka nie musi być dzieckiem elementu <body />.
Więc każesz rodzicowi tej tabelki ( deltab.parentNode ) usunąć tabelkę (deltab.parentNode.removeChild() ).

0
tMbRaga napisał(a)

Tutaj przy wyswietleniu "skacze" jak sie przejedzie myszka.

Musiałbyś pokazać ten efekt skakania, bo jakoś mi się nie chce wierzyć, że innerHTML jest szybsze, może to jakiś inny problem?

0

Efekt skakania, widoczny był tylko na IE. w ogóle wszystko na IE chodziło wolniej.
Teraz troche zmodyfikowalem skrypt i na razie cos nie działa pod IE, ale na razie głowie sie inna sprawa.

while (php_output[i] != undefined)
{
 var tr = document.createElement('tr');
 tbody.appendChild(tr);
 var td = document.createElement('td');
 td._str = php_output[i];
 td.appendChild(document.createTextNode(td._str));
 td.style.cursor = 'pointer';
 td.onmouseover = function() {
  this.style.backgroundColor = '#87CEFA'};
 td.onmouseout = function() {
  this.style.backgroundColor = '' };
 td.onclick = function () {document.getElementById('pole_formularza').value = td._str;};

 tr.appendChild(td);
 i++
}

Kod powyżej tworzy tabele, jednak problem polega na funkcji onclick, ktora ma przypisać zawartość z klikiętego TD do pola formularza.
Po kliknięciu na byle jaki TD przypisuje ona zawsze ostatni wiersz. Nie wazne czy wybiersze sie pierwszy ostatni czy trzydziesty piąty.
Jak naprawić ten mankament?

0
tMbRaga napisał(a)

Jak naprawić ten mankament?

zamiast ...value = td._str; spróbuj ...value = this._str;

0

Zadziałało, dzieki.
Jednak coraz to pojawiaja sie nowe problemy. Robie to tak troche po omacku.

Jak wspomniałem, chce zrobić taka prosta wyszukiwarke. To znaczy ktos wpisuje pierwsze 2 litery szukanej frazy do formularza, a ten odwołuje sie przez Ajax do PHP i wyciąga tablice z danymi na której to podstawie mozna wygenerować ładny box pod formularzem z podswietlanymi rekordami.
Po kliknięciu rekord ma być przepisany do formularza.

Generalnie chciałbym zrobić kilka takich dynamicznych formularzy na stronie.
Z ktorych kazdy by miał inny typ. To znaczy jeden by wyswietlał jakies imiona, drugi nazwiska.

Najpierw robiłem to strukturalnie, ale jak potem zorientowałem sie ze ma być kilka takich formularzy, to lepiej bedzie stworzyć klase, na której to podstawie bede tworzył obiekty.

Jako przykład kilka fotek ze znanych serwisów, gdzie zastosowano takie coś:
http://img248.imageshack.us/my.php?image=fotka2gu9.jpg
http://img142.imageshack.us/my.php?image=fotka3kf8.jpg
http://img168.imageshack.us/my.php?image=fotka4ff9.jpg

Mam pare pytań.
Na jakiej zasadze sie opiera cały ten box? Tabela czy nie?
Gdzie sa wyswietlane dane na temat szukania, czyli "Wyszukiwanie",
"Nie znaleziono". W tym samym boxie, czy oddzielny div?

Jak zrobić, by ten nowo utworzony box przykrył nowe elementy, a nie przykrywał je? Pozycjonowanie z-index?

Tutaj jest mój kod:

<?php
require("export_sajax.php");
?>

<html>
<head>

<style type="text/css"> 
td {border: 1px solid black;}

}
</style>

<script type="text/javascript"><? sajax_show_javascript(); ?></script>

<script type="text/javascript">

function nfosource(divid, type, inputid)
{
var divid = divid
var type = type
var inputid = inputid
var tmpThis = this;

this.export = function () {
if (document.getElementById("moja_tabela"))
{
	this.del();
}

var content = document.getElementById(inputid).value;
	if (content.length >=2)
	{  
	 this.loadnfo();
	 if (window.timerId) {clearTimeout(window.timerId);}
	 window.timerId = setTimeout(function() {
        tmpThis.send(content);}, 1000);
	}
	else
	{
	this.del();
	this.cleannfo();
	}
};



this.send = function (x) {
x_search_cpu(x, type, this.generate)
};

this.novaluesnfo = function () {
document.getElementById(divid).innerHTML = "Brak rekordów wg podanego klucza";
this.del();
};

this.loadnfo = function () {
document.getElementById(divid).innerHTML = "Trwa szukanie rekordów";
};

this.cleannfo = function () {
document.getElementById(divid).innerHTML = "";
};

this.del = function () {
var deltab = document.getElementById("moja_tabela");
deltab.parentNode.removeChild(deltab);
};

this.generate = function (php_output) {
var table = document.createElement('table');
var tbody = document.createElement('tbody'); 
table.id = 'moja_tabela'
table.appendChild(tbody);
var i=0

while (php_output[i] != undefined)
{
 var tr = document.createElement('tr');
 tbody.appendChild(tr);
 var td = document.createElement('td');
 td._str = php_output[i];
 td.appendChild(document.createTextNode(td._str));
 td.style.cursor = 'pointer';
 td.onmouseover = function() {
  this.style.backgroundColor = '#87CEFA' };
 td.onmouseout = function() {
  this.style.backgroundColor = '' };
 td.onclick = function() {
  document.getElementById(inputid).value = this._str; tmpThis.del();};

 tr.appendChild(td);
 i++
}

if (php_output[0] != undefined)
{	
	tmpThis.cleannfo();
	document.body.appendChild(table);
}

else
{
	tmpThis.novaluesnfo();
}};



}

var tabela = new nfosource("cpu_table", "1", "pole1")
</script>
</head>

<body>

<form>
<input type="text" id="pole1" onkeyup="tabela.export()">
</form>

<div id ="cpu_table"></div>

</body>
</html>

Generalnie w tym układzie mam problemy ze stworzeniem nowej tabeli czyli tego całego box-a, zaraz po znaczniku <form>, oraz by nowo powstała tabela była zawsze równo pod <form> i przykryła elementy znajdujące sie za nowo wygenerowaną tabelą.

Kod nie działa pod IE, natomiast działa pod Opera i Firefoxem

poza tym nie wiem czy nie dało by sie łatwiej definiować zależnosci miedzy skryptem, a html-em:

var tabela = new nfosource("cpu_table", "1", "pole1")

<body>
<form>
<input type="text" id="pole1" onkeyup="tabela.export()">
</form>
<div id ="cpu_table"></div>
</body>

Nie jasny dla was może być kod:

this.send = function (x) {
x_search_cpu(x, type, this.generate)
};

To jest SAJAX, ktory łączy funkcje z PHP do JS.
Ogólnie funkcja send dostaje dane z formularza, oczywiście nie bezpośrednio.
Najpierw inne funkcje sprawdzają, czy ktos skonczyl pisać, czy ma wiecej niz 2 znaki itd.

Następnie "wirtualną" funkcją search_cpu (napisaną w PHP) przekazuje jej dane z formularza, typ danych i funkcje do której przegenerowane dane mają powrócić.

Czyli PHP otrzymuje pewien ciąg danych, następnie łączy sie z MySQL-em sprawdza w bazie czy sa wyniki podobne do podanego ciągu danych i zwraca rekordy w postaci tablicy poprzez SAJAX do funkcji this.generate co jest trzecim parametrem wywołania x_search_cpu.

Dla rozjaśnienia gotowy przykład mojego kodu mozna znaleźć tutaj:
Link przeniesiony do postu niżej.

Jak klucz prosze wpisać generalnie nazwy procesorów, czyli Ath (od Athlon), Pal (od Palomino).
Pent (Pentium) itd.

Prosze o jakiś komentarz, czy generalnie idea jest zła czy nie.
Jezeli mozna to prosze wskazać poprawki dotyczące kodu. Moze tam być troche głupot, ponieważ nie mam dużego doświadczenia w JS.

Pozdrawiam.

0

Kwestia ostylowania. Ja np robie to na liście nieuporządkowanej. Dodane trochę ostylowania i gotowe. Jak chcesz wiedzieć jak jest to zrobione tam - zajrzyj po prostu w źródło. Np firebugiem gdy podpowiadanie jest wyświetlane.

0

Jak zmusić ten kod do działania pod Internet Explorer?
Dlaczego atrybut background-color jest widoczny dla IE nawet jeśli Div jest pusty?
W Operze i FF i jest wszystko dobrze, tylko ten IE zawsze robi problemy.

0

Pusty w sensie nie ma tekstu? Pusty jest gdy nie ma nawet białego znaku :> IE nie pozwala na zmniejszenie wysokości na mniej niż ma wysokość czcionki/linii (czy coś w tych okolicach).

0

Pusty, czyli mam na myśli

<div style = 'background-color:red'></div>

Skoro nie pozwala to jedynym wyjsciem jest usuniecie chyba tego background-color nie?

Hmm, a wiesz nav co z tym kodem, ze nie działa pod IE?
Z miłą chęcia sam bym go przeanalizował, ale niewiem pod jakim kątem IE jest wybredne.
Moze wiesz na co zwrocic uwage?

1 użytkowników online, w tym zalogowanych: 0, gości: 1