Vanya pergi ke adaptif dinamis atau nenek JavaScript

Saat bekerja pada adaptif, kita sekarang dan kemudian harus mengubah penampilan objek. Biasanya cukup bagi kami untuk mendaftarkan beberapa pertanyaan media dan kami bisa melakukannya. Dalam beberapa kasus, kita perlu mengubah urutan elemen, dan di sini, misalnya, properti pesanan dari teknologi Flexbox atau Grid datang untuk menyelamatkan. Tetapi ada saat-saat ini tidak membantu kita.

Gagasan adaptif dinamis dirancang untuk menyederhanakan kehidupan desainer tata letak dan dengan cepat mengadaptasi elemen tata letak yang kompleks.


Sebagai contoh, lihat kasus ini. Di sini kita memiliki struktur berikut: heading dan beberapa teks.



Tetapi dengan izin tertentu, perancang menunjukkan bahwa teks yang berada di bawah judul sekarang harus berada di tempat yang sama sekali berbeda dalam struktur.



Biasanya, desainer tata letak memecahkan masalah ini dengan salah satu dari dua cara. Saya akan segera mengingatkan Anda tentang mereka.

Saya akan menunjukkannya sebagai contoh situasi kehidupan ketika bocah kota Vanya benar-benar ingin datang ke neneknya selama musim panas. Tetapi bukan karena dia merindukan neneknya, tetapi karena dia ingin pergi ke sungai bersama gadis Olya. Dan dia ingin melakukan ini pada resolusi di bawah 992px.



Bagaimana kita memecahkan masalah Vani?
Kita dapat melakukan hal berikut: Sembunyikan Vanya di kota atas izin ini, dan tunjukkan Vanya di sungai dengan Olya. Tapi untuk ini kita perlu membuat klon dari Vani.
Inilah kota (asli) Vanya. Tapi Vanya, pada kenyataannya, di sungai sudah bersama Olya.



Namun awalnya Vanya sungai ini disembunyikan dalam CSS. Kami menulis kueri media dengan parameter yang kami butuhkan, di mana kami menampilkan Vanya yang baru, dan menyembunyikan Vanya yang lama (kota).



Semuanya bekerja untuk kita - atas izin yang kita butuhkan, Vanya menemukan dirinya di bawah Olya.



Dengan demikian, ketika resolusi lebih besar dari 992px, Vanya segera kembali ke kota.



Dan sepertinya semuanya baik-baik saja, Vanya dengan Olya saat dibutuhkan. Anda dapat membubarkan ...

Tapi tidak sesederhana itu. Bahkan, beberapa pelanggan sangat menentang duplikat konten. Ini disebabkan oleh beberapa masalah dengan SEO, dan, pada prinsipnya, pembuatan blok yang tidak perlu.

Sekarang kita beruntung, dalam situasi kita, Vanya agak kecil, dan Vanya kebetulan sangat besar, masif, dipompa kawan, yang masing-masing membutuhkan banyak baris kode. Dan dalam situasi ini, termasuk pelanggan, mereka meminta Anda untuk memindahkan objek DOM menggunakan JavaScript.

Ini dapat dilakukan kira-kira sebagai berikut. Untuk memulainya, saya harus menghapus Vanya, yang merupakan klon, dalam HTML dan meninggalkan Vanya yang asli. Di CSS, komentari semua baris yang awalnya kami miliki untuk opsi pembungkus lain. Dan tambahkan di sini kode JS yang sederhana.

// 
const parent_original = document.querySelector('.content__blocks_city');
const parent = document.querySelector('.content__column_river');
const item = document.querySelector('.content__block_item');

//   
window.addEventListener('resize', move);

//
function move(){
	const viewport_width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
	if (viewport_width <= 992) {
		if (!item.classList.contains('done')) {
			parent.insertBefore(item, parent.children[2]);
			item.classList.add('done');
		}
	} else {
		if (item.classList.contains('done')) {
			parent_original.insertBefore(item, parent_original.children[2]);
			item.classList.remove('done');
		}
	}
}

// 
move();

Pertama, kita mendeklarasikan variabel di mana kita "memanggil" ke kota, sungai dan Vani asli. Selanjutnya, kita mulai "mendengarkan" lebar layar untuk menangkap momen ketika kita perlu memindahkan Vanya. Setelah kami mendapatkan lebar dan mengatur kondisi di mana kami memeriksa bahwa lebarnya kurang dari atau sama dengan 992px. Saat memindahkan Vanya, kami memberikan kelas kepadanya, jadi kami memeriksa keberadaan kelas sehingga gerakan ini tidak terjadi setiap saat (Vanya bergerak sekali dan hanya itu, Anda tidak perlu terus-menerus mentransfernya). Dan kami melakukan transfer itu sendiri di dalam induk (ke sungai), di sini kami menunjukkan posisi di pohon DOM di mana kita perlu memindahkan Vanya (di bawah Olya, di atas Olya). Dan ketika kita memiliki resolusi lebih besar dari 992px, kita harus mengembalikan Vanya ke tempat itu.

Kami mencoba dan melihat bahwa Vanya kami kembali bergerak di bawah Olya.

Dan semuanya baik-baik saja: kami tidak memiliki konten duplikat, semuanya berfungsi dengan baik, pelanggan puas, semua orang senang. Tetapi metode ini memiliki sejumlah masalah yang terkait dengan penulisan kode js itu sendiri.
Kami memahami bahwa untuk satu kasus, ini normal - kami menulis dengan baik. Tetapi saya mendapat ide untuk mengotomatiskan proses ini. Misalkan saya perlu melemparkan 5-6 elemen yang sama sekali berbeda pada halaman. Untuk tugas ini, menulis kode js menggunakan metode ini cukup melelahkan dan memakan waktu. Dan poin kedua, yang, tentu saja, membuat Anda tegang, adalah beban pada PC pengguna, karena di sini kita terus-menerus "mendengarkan" lebar layar. Saya juga ingin mengoptimalkan momen ini. Itu dapat dioptimalkan dalam kode ini juga, tetapi karena saya menulis alat otomatisasi yang saya sebut "adaptive dinamis" , saya dioptimalkan di sana.

Sekarang saya akan menunjukkan cara kerjanya.

Setelah menghubungkan adaptif dinamis saya, saya hanya perlu bekerja dengan file HTML dan tidak perlu mengakses JavaScript. Untuk melakukan ini, saya perlu menulis atribut data-da (da adalah kependekan dari adaptif dinamis) dan menentukan tiga parameter dalam tanda kutip, dipisahkan dengan koma.
Parameter pertama adalah di mana. Saya mengambil kelas objek yang unik di mana saya ingin memindahkan Vanya.
Parameter kedua adalah yang (berturut-turut). Objek saya memiliki dua elemen: nol dan yang pertama (kita tahu bahwa di JavaScript semuanya dimulai dari awal). Saya perlu memasukkan Vanya setelah objek "1", jadi saya menulis parameter "2".

Parameter ketiga adalah kapan. Pada parameter ketiga, saya menulis "992", ini adalah resolusi di bawah ini yang Vanya benar-benar ingin dapatkan ke Olya.

Parameter kedua dan ketiga adalah opsional. Secara default, objek akan dipindahkan ke ujung blok dengan resolusi di bawah 768px.



Kami memeriksa. Semuanya berfungsi sama seperti di versi sebelumnya, tetapi tanpa duplikasi konten dan semuanya otomatis.

Pertimbangkan fasilitasnya.

Sekarang, untuk memindahkan Vanya ke Olya, saya hanya perlu mengubah nomor seri di parameter atribut kedua. Dan Vanya sudah akan melewati Olya.



Nyaman bukan? Saya dapat melakukan hal yang sama dengan parameter breakpoint ketiga. Saya dapat menentukan, misalnya, 1280px. (data-da = "content__column_river, 1,1280"). Jadi Vanya akan pergi ke Olya sedikit lebih awal, tepatnya ketika nilai ini tercapai. Dan yang paling keren adalah Vanya akan kembali ke tempatnya secara otomatis.

Untuk menambah kenyamanan, alih-alih nomor seri pada parameter kedua atribut, Anda dapat menentukan satu dari dua nilai - pertama atau terakhir. Ketika saya menulis pertama kali, Vanya akan bergerak di atas judul "Saya seorang sungai." Ini akan terletak paling pertama di dalam objek tempat kita mengirimnya. Dengan demikian, jika Anda menentukan yang terakhir, maka Vanya kami akan berada di paling bawah objek.



Mari kita lihat beberapa contoh lagi. Misalkan kita dapat mengirim Kolya ke taman lota, dan mengirim Anya ke sungai ke Van dan Ola juga, itu akan lebih menyenangkan. Kami menulis untuk Kolya atribut dengan parameter
data-da = "content__column_garden, 2,992" . Dan untuk Ani kita menulis data-da = "content__column_river, 1.1280"

Kita melihat: Anya, Olya dan Vanya di sungai. Kolya pergi ke Lota beberapa saat kemudian. Setelah kembali, semua pria ada di tempat mereka. Semuanya bagus.

Bermain-main di CodePen: codepen.io/FreelancerLifeStyle/project/full/ZmWOPm

Tentu saja, Anda mungkin memiliki pertanyaan: bagaimana dengan acara yang dapat digantung pada objek yang dapat dipindahkan? Sebagai contoh, pada awalnya, ketika mengklik Anya, kita mendapatkan jendela dengan tulisan: "Semuanya baik-baik saja." Mari kita lihat apa yang terjadi ketika dia bergerak bersama para pria ke sungai.
Pindahkan, buat klik - semuanya berfungsi dengan baik, jendela juga ditampilkan. Acara tetap dengan objek saat dipindahkan.



Dan pertanyaan kedua yang menarik adalah beban, yang saya coba meminimalkan. Sekarang saya akan menunjukkan ini dengan menceritakan sedikit tentang kode yang tersembunyi di bawah kap adaptif dinamis.

Pertama-tama, saya mendeklarasikan beberapa variabel, termasuk membuat array, yang saya isi di bawah ini. Saya mendapatkan atribut, pisahkan, mengubahnya menjadi array untuk mendapatkan elemen individual. Selanjutnya, saya mengisi posisi asli benda-benda itu sehingga mereka dapat dikembalikan ke tempat orang tua mereka (di kota). Setelah itu, saya mengisi array elemen sendiri, sehingga saya bisa mengurutkannya untuk operasi yang benar.

let originalPositions = [];
let daElements = document.querySelectorAll('[data-da]');
let daElementsArray = [];
let daMatchMedia = [];
// 
if (daElements.length > 0) {
	let number = 0;
	for (let index = 0; index < daElements.length; index++) {
		const daElement = daElements[index];
		const daMove = daElement.getAttribute('data-da');
		if (daMove != '') {
			const daArray = daMove.split(',');
			const daPlace = daArray[1] ? daArray[1].trim() : 'last';
			const daBreakpoint = daArray[2] ? daArray[2].trim() : '767';
			const daDestination = document.querySelector('.' + daArray[0].trim())
			if (daArray.length > 0 && daDestination) {
				daElement.setAttribute('data-da-index', number);
				//   
				originalPositions[number] = {
					"parent": daElement.parentNode,
					"index": indexInParent(daElement)
				};
				//   
				daElementsArray[number] = {
					"element": daElement,
					"destination": document.querySelector('.' + daArray[0].trim()),
					"place": daPlace,
					"breakpoint": daBreakpoint
				}
				number++;
			}
		}
	}
	dynamicAdaptSort(daElementsArray);

	//    
	for (let index = 0; index < daElementsArray.length; index++) {
		const el = daElementsArray[index];
		const daBreakpoint = el.breakpoint;
		const daType = "max"; // MobileFirst   min

		daMatchMedia.push(window.matchMedia("(" + daType + "-width: " + daBreakpoint + "px)"));
		daMatchMedia[index].addListener(dynamicAdapt);
	}
}

Dan pada akhirnya, optimasi yang saya bicarakan diimplementasikan: alih-alih mengubah ukuran jendela (mendengarkan setiap perubahan jendela), kita hanya akan mendengarkan perubahan di breakpoint menggunakan window matchMedia. Dengan cara ini kami mendapatkan respons browser hanya di beberapa titik: yang kami tunjukkan dalam atribut objek kami.

Selanjutnya, saya mengumpulkan array dari breakpoints ini dan menggantung acara untuk setiap breakpoints. Dalam fungsi dynamic_adapt utama, saya perluas semua ini di dalam array yang kami kumpulkan dan disortir, periksa keberadaan breakpoint, pindahkan elemen, atau kembalikan ke tempat mereka.

// 
function dynamicAdapt(e) {
	for (let index = 0; index < daElementsArray.length; index++) {
		const el = daElementsArray[index];
		const daElement = el.element;
		const daDestination = el.destination;
		const daPlace = el.place;
		const daBreakpoint = el.breakpoint;
		const daClassname = "_dynamic_adapt_" + daBreakpoint;

		if (daMatchMedia[index].matches) {
			// 
			if (!daElement.classList.contains(daClassname)) {
				let actualIndex = indexOfElements(daDestination)[daPlace];
				if (daPlace === 'first') {
					actualIndex = indexOfElements(daDestination)[0];
				} else if (daPlace === 'last') {
					actualIndex = indexOfElements(daDestination)[indexOfElements(daDestination).length];
				}
				daDestination.insertBefore(daElement, daDestination.children[actualIndex]);
				daElement.classList.add(daClassname);
			}
		} else {
			//  
			if (daElement.classList.contains(daClassname)) {
				dynamicAdaptBack(daElement);
				daElement.classList.remove(daClassname);
			}
		}
	}
	customAdapt();
}

Kembali ke fungsi posisi asal:

//   
function dynamicAdaptBack(el) {
	const daIndex = el.getAttribute('data-da-index');
	const originalPlace = originalPositions[daIndex];
	const parentPlace = originalPlace['parent'];
	const indexPlace = originalPlace['index'];
	const actualIndex = indexOfElements(parentPlace, true)[indexPlace];
	parentPlace.insertBefore(el, parentPlace.children[actualIndex]);
}

Secara alami, banyak yang memiliki pertanyaan tentang Mobile First. Tidak ada masalah - kita hanya perlu mengubah beberapa variabel dalam kode (menghapus pengaturan ini dalam HTML sudah berfungsi):

  1. Ketika saya mengumpulkan array breakpoint, kita perlu mengubah "maks" menjadi "min" di sini. Dan acara tersebut akan "didengarkan" bukan oleh max-width, tetapi oleh min-width.
  2. Anda juga perlu mengubah pengurutan agar objek dalam array disejajarkan dalam urutan yang berbeda saat kami mengurutkannya berdasarkan breakpoint.

	// 
	function dynamicAdaptSort(arr) {
		arr.sort(function (a, b) {
			if (a.breakpoint > b.breakpoint) { return -1 } else { return 1 } // MobileFirst 
		});
		arr.sort(function (a, b) {
			if (a.place > b.place) { return 1 } else { return -1 }
		});
	}

Juga dalam adaptive dinamis, saya menggunakan metode tertentu untuk mendapatkan indeks ketika objek dilempar. Dan ini adalah kelemahan pertama - saya harus mengecualikan objek yang ditransfer. Itu ketika saya mentransfer objek ke tempat yang sama, sehingga semuanya memadai dan objek berbaris dalam urutan yang kita inginkan, saat mentransfer, saya perlu mengecualikan objek yang sebelumnya ditransfer ke titik yang sama.

//       
function indexOfElements(parent, back) {
	const children = parent.children;
	const childrenArray = [];
	for (let i = 0; i < children.length; i++) {
		const childrenElement = children[i];
		if (back) {
			childrenArray.push(i);
		} else {
			//  
			if (childrenElement.getAttribute('data-da') == null) {
				childrenArray.push(i);
			}
		}
	}
	return childrenArray;
}

Tetapi membutuhkan masalah penyortiran lainnya. Misalnya, jika saya mentransfer orang-orang pada saat yang sama ke posisi yang sama, saya tidak akan dapat mengontrol pesanan mereka.

Salah satu cara untuk mengembangkan adaptasi dinamis ini dapat, misalnya, penciptaan beberapa breakpoints. Contoh, kita perlu memindahkan Vanya ke Ola pada 1280px, dan pada 992px Vanya untuk pindah ke taman, atau kembali ke tempat itu. Fungsi ini tidak tersedia sekarang, jadi masih ada pekerjaan yang harus dilakukan. Secara umum, untuk mencakup 95% tugas sehari-hari secara adaptif, fungsi yang sekarang sudah cukup bagi saya. Untuk menyelesaikan masalah memindahkan item ke tempat lain, saya perlu menghabiskan beberapa detik untuk menulis atribut. Dan saya akan mendapatkan hasil yang saya butuhkan.

Secara alami, saya mendesak semua orang yang menyukai adaptive dinamis untuk mengambil bagian dalam pengujian, pengembangan dan peningkatan fungsional dan optimalisasi kode itu sendiri. Dan semuanya agar Kohl, Ani, Vani, dan Olya kita akan bersama ketika mereka menginginkannya.

Repositori GitHub - github.com/FreelancerLifeStyle/dynamic_adapt

Berdasarkan video " Dynamic Adaptive // ​​Fast Adaptation of Objects Complex in JavaScript " di saluran youtube " Freelancer for Life "

All Articles