فهرست
1 - مقدمه
2 - مبانی کاتلین/JS
3 - همکاری با JS
4 - بقیه فصل ها در حال ساخت است
کار با DOM - بخش اول
امروز بهتون یادمیدم که چطور بتونین با DOM
از داخل برنامه جاوااسکریپتتون کارکنین.
اگه یادتون باشه یک برانامه نوشتیم که کنسول رو صدا میزد و Hello, World
رو داخلش چاپ میکرد و همینطور یک فایل index.html
ساختیم که بتونیم نتیجه رو نمایش بدیم. خب حالا به قسمتی رسیدیم که میخوایم با DOM
ارتباط برقرار کنیم. قبل از این که داخل Main.kt
کدی بزنیم لازمه که یک سری تغییرات توی فایل index.html
بدیم:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Working With DOM</title>
</head>
<body>
<div id="root"></div>
<script src="out/production/KotlinJSHelloWorld/lib/kotlin.js"></script>
<script src="out/production/KotlinJSHelloWorld/KotlinJSHelloWorld.js"></script>
</body>
</html>
خب کاری که کردیم درواقع تنها اضافه کردن یک div
به فایل html امون بود که بتونیم از طریق کد جاوا اسکریپتمون باهاش ارتباط برقرار کنیم.
حالا میتونیم از طریق کد کاتلین باهاش ارتباط برقرار کنیم. برگردیم به Main.kt
و کد زیر رو اضافه کنیم:
document.getElementById("root")
درواقع کدی که زدیم میاد عنصری که با ای دی root
وجود داره رو صدا میزنه که بعدا میتونیم ازش استفاده کنیم.
ولی یه سوال…. اینجا داریم با پاس دادن یه رشته یک عنصر رو صدا میزنیم.اگه اشتباه تایپی داشته باشیم و یا اصا به هر دلیلی یک عنصر null
رو صدا بزنیم چه اتفاقی میفته.
درواقع موقع صدازندش اتفاقی نمیفته، وقع استفاده کردنش منجر به بروز اتفاق میشه.مثلا کد زیر رو نگاه کنین:
val root = document.getElementById("root1")
root.innerHTML = "<h1>Hello, World again!</h1>"
توی کاتلین اگه همچین کدی رو بنویسین، کامپایلر توی خط دوم بهتون ارور میده! دلیلش هم اینه کا کاتلین امنه! کاتلین(اگه درست ازش استفاده کنین) امنه! اجازه نمیده از عنصری که ممکنه null
باشه استفاده کنین. برای حل این مشکل چندین راه حل دارین. اولیش اینه که از روش قدیمی استفاده کنیم، یعنی :
fun main(args: Array<String>) {
println("Hello, World!")
val root = document.getElementById("root")
if (root != null) {
root.innerHTML = "<h1>Hello, World again!</h1>"
}
println("The end")
}
الان اگه این کد رو بیلد کنین، نتیجه رو توی مرورگر اینجوری میبینین:
اگه root به root1 تغییر کنه، یعنی مثلا کد زیر:
val root = document.getElementById("root1")
نتیجه اینجوری ظاهر میشه:
همینطور که میبینین چون عنصری رو صدا زدیم که null
بود مقدارش چاپ نشد. ولی این خوبه اگه یادمون باشه که قبلش null
رو چک کنیم و دقیقا زمان هایی به وجود میاد که یادمون میره همچین کاری انجام بدیم.
راه حل دیگه استفاده از عملگر !!
هه. درواقع این عملگر درکاتلین اومده که تنها ارور در زمان کامپایلرو از بین ببره و در واقع توسعه دهنده با صدازدن همچین عملگری به کامپایلر میگه: “ تو کاریت نباشه، من میدونم چیکار دارم میکنم”. بیاین ازش استفاده کنیم و نتیجه هارو ببینیم :
fun main(args: Array<String>) {
println("Hello, World!")
val root = document.getElementById("root")
root!!.innerHTML = "<h1>Hello, World again!</h1>"
println("The end")
}
و نتیجه :
همینطور که میبینین وقتی عنصر درستی رو صدا بزنیم، برنامه درست کار میکنه. ولی وقتی root1 رو صدا بزنیم:
متوجه میشیم که به NullPointerException
میخوریم و متاسفانه این مسئله خیلی از موقع ها پیش میاد و باعث بروز مشکل در سیستم میشه. به همین خاطر به این ارور ها، ارورهای میلیون دلاری هم گفته میشه.
ولی راه حل درستی که کاتلین پیشنهاد میکنه استفاده از عملگر ?
هه . کد زیر رو نگاه کنین:
در واقع وقتی کامپایلر به اون نقطه میرسه نگاه میکنه، اگه عنصری که داره ازش استفاده میشه null
نبود، عمل لازم رو روش انجام میده، ولی اگر null
بود از روی اون خط رد میشه.
خب معلومه که اگه این کد رو اجرا کنیم نتیجه درست و دلخواهمون رو میگیریم.بذارین با root1
اجرا کنیم و نتیجه رو ببینیم:
خب همینطور که میبنین، همون نتیجه که میخواستیم رو گرفتیم و علاوه بر اون چون کامپایلر بهمون موقع کدنویسی ارور میده، خودمون قبل از اجرا متوجه میشیم و با استفاده از این عملگر از اجراش جلوگیری میکنیم.
حالا اگه توسعهدهنده که ما باشیم بخواد اگه null
دریافت کرد کار دیگه ای رو انجام بده(مثلا موقعی که null
دریافت کرد یک رشته رو چاپ کنه) اون موقع باید چیکار کنه. کاتلین اینجا هم راه حل داره. کد زیر رو نگاه کنین:
fun main(args: Array<String>) {
println("Hello, World!")
val root = document.getElementById("root1")
println("root is $root")
root?.innerHTML = "<h1>Hello, World again!</h1>"
println("The end")
}
در واقع یکی از خوبیای کاتلین اینه! کاتلین وقتی یک شی null
رو برای print
دریافت میکنه، مقدار null
رو هم چاپ میکنه.یعنی میتونین نه تنها ارور error
نمیده، بلکه میتونین ازش استفاده کنین.الان اگه این کد رو اجرا کنین نتیجه زیر رو میبینین:
همینطور که میبینین مقدار null
رو چاپ میکنه.
حالا بیاین کد html
ای که میخوایم به div
اضافه کنیم رو یکم مشکلتر کنیم، یک کد چندخطی استفاده کنیم.
fun main(args: Array<String>) {
println("Hello, World!")
val message = "KotlinFarsi"
val html = """
<h1>Hello, World again!</h1>
<p>KotlinFarsi contains ${message.length} letters</p>
"""
val root = document.getElementById("root")
root?.innerHTML = html
println("The end")
}
توی این کد چندتا نکته جدید داریم. یکی این که از یک متغییر برای نوشتن کد چندخطی html
استفاده کردیم و برای این که به کامپایلر بفهمونیم کدمون چندخطیه، کد html
رو داخل یک جفت """
قرار دادیم. و همینطور فهمیدیم که اگه بخوایم میتونیم داخل رشته هم از مقدار یک متغیر استفاده کنیم. درواقع زمانی که از {}$
استفاده میکنیم، کامپایلر هرچی داخل اکولادها بنویسین رو به عنوان یک کد حساب میکنه، نه رشته، و در انتها مقدار اون کدی که نوشتیم رو به صورت رشته چاپ میکنه.
خروجی کد بالا :
حالا بیاین یک دکمه به html اضافه کنیم. دکمه ای که وقتی روش کلیک شد یک عبارت رو چاپ کنه
fun main(args: Array<String>) {
println("Hello, World!")
val message = "KotlinFarsi"
val html = """
<h1>Hello, World again!</h1>
<p>KotlinFarsi contains ${message.length} letters</p>
<button id="btn">Click Me</button>
"""
val root = document.getElementById("root")
root?.innerHTML = html
val btn = document.getElementById("btn")
btn?.addEventListener("click",{ println("Clicked") })
println("The end")
}
اومدیم به متغییر html یک دکمه اضافه کردیم و توی کدمون یک EventListener
و زمانی که برروی دکمه کلیک میشه “Clicked” توی کنسول به نمایش در میاد.
قبل از فشار دادن دکمه:
و بعد از فشار دادن دکمه :
همینطور که میبینین وقتی دکمه رو فشار دادیم Clicked چاپ شد.