API'lerle Etkileşimli Bir Hava Durumu Gösterge Tablosu Oluşturmak için Vue.js'yi Kullanma

Yayınlanan: 2022-03-10
Hızlı özet ↬ API verileriyle bir gösterge panosu oluşturmak genellikle karmaşık bir iştir. Teknoloji yığınınızı seçmek, API'leri entegre etmek, doğru çizelgeleri seçmek ve CSS stilleriyle güzelleştirmek zor olabilir. Bu eğitici, API verilerini kullanarak Vue.js'de bir hava durumu panosu oluşturmanıza nasıl yardımcı olacağınıza ilişkin adım adım bir kılavuzdur.

(Bu, sponsorlu bir makaledir.) Bu eğitimde, sıfırdan basit bir hava durumu panosu oluşturacaksınız. Ne bir “Merhaba Dünya” örneği ne de boyutu ve karmaşıklığı açısından çok korkutucu olmayan bir istemci-uç uygulama olacaktır.

Tüm proje, Node.js + npm ekosistemindeki araçlar kullanılarak geliştirilecektir. Özellikle, veriler için Dark Sky API'sine, tüm ağır işler için Vue.js'ye ve veri görselleştirme için FusionCharts'a büyük ölçüde güveneceğiz.

Önkoşullar

Aşağıdakilere aşina olduğunuzu umuyoruz:

  • HTML5 ve CSS3 (Bootstrap tarafından sağlanan temel özellikleri de kullanacağız;
  • JavaScript (özellikle dili kullanmanın ES6 yolu);
  • Node.js ve npm (çevre ve paket yönetiminin temelleri gayet iyi).

Yukarıda bahsedilenlerin dışında, Vue.js veya benzeri bir JavaScript çerçevesi hakkında bilginiz varsa harika olur. FusionCharts hakkında bilgi sahibi olmanızı beklemiyoruz - kullanımı o kadar kolay ki, anında öğreneceksiniz!

Beklenen Öğrenmeler

Bu projeden öğreneceğiniz temel bilgiler şunlar olacaktır:

  1. İyi bir gösterge panosunun uygulanması hakkında nasıl plan yapılır?
  2. Vue.js ile uygulamalar nasıl geliştirilir?
  3. Veriye dayalı uygulamalar nasıl oluşturulur?
  4. FusionCharts kullanarak veriler nasıl görselleştirilir

Özellikle, bölümlerin her biri sizi öğrenme hedeflerine bir adım daha yaklaştırıyor:

  1. Hava Durumu Gösterge Tablosuna Giriş
    Bu bölüm size girişimin farklı yönlerine ilişkin bir genel bakış sunar.
  2. Projeyi Oluştur
    Bu bölümde, Vue komut satırı aracını kullanarak sıfırdan bir proje oluşturmayı öğreneceksiniz.
  3. Varsayılan Proje Yapısını Özelleştirin
    Bir önceki bölümde aldığınız varsayılan proje iskelesi yeterli değildir; burada proje için gerekli olan ek şeyleri yapısal bir bakış açısından öğreneceksiniz.
  4. Veri Toplama ve İşleme
    Bu bölüm projenin eteğidir; API'den veri almak ve işlemek için tüm kritik kodlar burada gösterilmektedir. Bu bölümde maksimum zaman geçirmeyi bekleyin.
  5. FusionCharts ile Veri Görselleştirme
    Tüm verileri ve projenin diğer hareketli kısımlarını stabilize ettikten sonra, bu bölüm verileri FusionCharts ve biraz CSS kullanarak görselleştirmeye ayrılmıştır.

1. Pano İş Akışı

Uygulamaya geçmeden önce planımız hakkında net olmak önemlidir. Planımızı dört farklı yöne ayırıyoruz:

Gereksinimler

Bu proje için gereksinimlerimiz nelerdir? Başka bir deyişle, Hava Durumu Panomuz aracılığıyla sergilemek istediğimiz şeyler nelerdir? Hedef kitlemizin muhtemelen basit zevklere sahip ölümlüler olduğunu akılda tutarak, onlara aşağıdakileri göstermek istiyoruz:

  • Hava durumunu görmek istedikleri konumun ayrıntıları ve hava durumuyla ilgili bazı temel bilgiler. Sıkı bir gereklilik olmadığı için sıkıcı detayları daha sonra anlayacağız. Ancak, bu aşamada, hedef kitleye ilgi duydukları konum için girdi sağlayabilmeleri için bir arama kutusu sağlamamız gerekeceğini belirtmek önemlidir.
  • İlgilendikleri yerin hava durumu hakkında aşağıdakiler gibi grafiksel bilgiler:
    • Sorgu günü için sıcaklık değişimi
    • Bugünkü havanın öne çıkan özellikleri:
      • Rüzgar Hızı ve Yönü
      • görünürlük
      • UV Endeksi

Not : API'den elde edilen veriler, hava durumunun diğer birçok yönü hakkında bilgi sağlar. Kodu minimumda tutmak adına hepsini kullanmamayı seçiyoruz.

Yapı

Gereksinimlere göre, gösterge tablomuzu aşağıda gösterildiği gibi yapılandırabiliriz:

Pano yapısı
(Büyük önizleme)

Veri

Kontrol panelimiz, aldığımız veriler kadar iyidir, çünkü uygun veriler olmadan güzel görselleştirmeler olmaz. Hava durumu verileri sağlayan çok sayıda genel API vardır - bazıları ücretsizdir ve bazıları değildir. Projemiz için Dark Sky API'sinden veri toplayacağız. Ancak, API uç noktasını doğrudan istemci ucundan yoklayamayacağız. Endişelenmeyin, tam zamanında ortaya çıkacak bir geçici çözümümüz var! Aranan konum için verileri aldığımızda, bazı veri işleme ve biçimlendirme işlemleri yapacağız - bilirsiniz, faturaları ödememize yardımcı olan teknik türler.

görselleştirme

Temiz ve biçimlendirilmiş veriler elde ettiğimizde, bunları FusionCharts'a bağlarız. Dünyada FusionCharts kadar yetenekli çok az JavaScript kitaplığı vardır. FusionCharts'ın sunduğu çok sayıda tekliften yalnızca birkaçını kullanacağız - tümü JavaScript ile yazılmıştır, ancak FusionCharts için Vue sarmalayıcı ile entegre edildiğinde sorunsuz çalışır.

Büyük resimle donanmış olarak ellerimizi kirletelim - işleri somutlaştırmanın zamanı geldi! Bir sonraki bölümde, üzerine inşa edeceğimiz temel Vue projesini oluşturacaksınız.

2. Proje Oluşturma

Projeyi oluşturmak için aşağıdaki adımları uygulayın:

  1. Node.js + npm'yi yükleyin
    ( Bilgisayarınızda Node.js kurulu ise bu adımı atlayın. )
    Node.js, npm ile birlikte gelir, bu nedenle npm'yi ayrıca yüklemeniz gerekmez. İşletim sistemine bağlı olarak, burada verilen talimatlara göre Node.js'yi indirin ve kurun.

    Yüklendikten sonra, yazılımın düzgün çalışıp çalışmadığını ve sürümlerinin ne olduğunu doğrulamak muhtemelen iyi bir fikirdir. Bunu test etmek için komut satırını/terminali açın ve aşağıdaki komutları yürütün:
     node --version npm --version
  2. Paketleri npm ile kurun
    Npm'yi çalıştırıp çalıştırdıktan sonra, projemiz için gerekli olan temel paketleri kurmak için aşağıdaki komutu yürütün.
     npm install -g vue@2 vue-cli@2
  3. vue-cli ile proje iskelesini başlatın
    Önceki adımın her şeyin yolunda gittiğini varsayarsak, sonraki adım, projeyi başlatmak için Vue.js'den bir komut satırı aracı olan vue-cli cli'yi kullanmaktır. Bunu yapmak için aşağıdakileri yürütün:
    • Webpack-simple şablonuyla iskeleyi başlatın.
       vue init webpack-simple vue_weather_dashboard
      Size bir sürü soru sorulacak - son soru dışında herkes için varsayılanları kabul etmek bu proje için yeterince iyi olacaktır; sonuncusu için cevap N
      Komut satırının/terminalinin ekran görüntüsü
      (Büyük önizleme)
      webpack-simple bizimki gibi hızlı prototipleme ve hafif uygulamalar için mükemmel olmasına rağmen, özellikle ciddi uygulamalar veya üretim dağıtımı için uygun olmadığını unutmayın. Başka bir şablon kullanmak istiyorsanız (ancak yeni başlayan biriyseniz bunu önermeyiz) veya projenize başka bir ad vermek istiyorsanız, sözdizimi şöyledir:
       vue init [template-name] [project-name]
    • Proje için vue-cli tarafından oluşturulan dizine gidin.
       cd vue_weather_dashboard
    • webpack-simple şablonu için vue-cli aracı tarafından oluşturulan package.json içinde belirtilen tüm paketleri kurun.
       npm install
    • Geliştirme sunucusunu başlatın ve varsayılan Vue projenizin tarayıcıda çalıştığını görün!
       npm run dev

Vue.js'de yeniyseniz, en son başarınızın tadını çıkarmak için bir dakikanızı ayırın - küçük bir Vue uygulaması oluşturdunuz ve bu uygulama localhost:8080'de çalışıyor!

Vue.js web sitesinin ekran görüntüsü
(Büyük önizleme)

Varsayılan Proje Yapısının Kısa Açıklaması

vue_weather_dashboard dizini içindeki yapıya bir göz atmanın zamanı geldi, böylece biz onu değiştirmeye başlamadan önce temelleri anlamış olursunuz.

Yapı şöyle bir şeye benziyor:

 vue_weather_dashboard |--- README.md |--- node_modules/ | |--- ... | |--- ... | |--- [many npm packages we installed] | |--- ... | |--- ... |--- package.json |--- package-lock.json |--- webpack.config.js |--- index.html |--- src | |--- App.vue | |--- assets | | |--- logo.png | |--- main.js

Varsayılan dosyalara ve dizinlere aşina olmayı atlamak cazip gelse de, Vue'da yeniyseniz, en azından dosyaların içeriğine bir göz atmanızı şiddetle tavsiye ederiz . İyi bir eğitim oturumu olabilir ve kendi başınıza takip etmeniz gereken soruları tetikleyebilir, özellikle aşağıdaki dosyalar:

  • package.json ve kuzeni package-lock.json bir bakış
  • webpack.config.js
  • index.html
  • src/main.js
  • src/App.vue

Ağaç şemasında gösterilen dosya ve dizinlerin her birinin kısa bir açıklaması aşağıda verilmiştir:

  • BENİOKU.md
    Tahmin için ödül yok - öncelikle insanların proje iskelesini oluşturmak için gerekli adımları okuması ve anlaması gerekiyor.
  • düğüm_modülleri/
    Bu, npm'nin projeyi başlatmak için gerekli paketleri indirdiği dizindir. Gerekli paketlerle ilgili bilgiler package.json dosyasında mevcuttur.
  • paket.json
    Bu dosya, webpack-simple şablonunun gereksinimlerine dayalı olarak vue-cli aracı tarafından oluşturulur ve yüklenmesi gereken npm paketleri (sürümleri ve diğer ayrıntıları dahil) hakkında bilgiler içerir. Bu dosyanın içeriğine yakından bakın - burası, proje için gerekli paketleri eklemek/silmek için ziyaret etmeniz ve belki de düzenlemeniz ve ardından npm kurulumunu çalıştırmanız gereken yerdir. package.json hakkında daha fazla bilgiyi buradan okuyun.
  • paket kilidi.json
    Bu dosya npm'nin kendisi tarafından oluşturulur ve öncelikle npm'nin indirdiği ve kurduğu şeylerin bir günlüğünü tutmak içindir.
  • webpack.config.js
    Bu, projemizin farklı yönlerini (kod, statik varlıklar, yapılandırma, ortamlar, kullanım modu vb.) bir araya toplayan ve kullanıcıya sunmadan önce küçülten bir araç olan web paketinin yapılandırmasını içeren bir JavaScript dosyasıdır. Avantajı, her şeyin otomatik olarak birbirine bağlanması ve uygulamanın performansındaki iyileşme nedeniyle kullanıcı deneyiminin büyük ölçüde artmasıdır (sayfalar hızlı bir şekilde sunulur ve tarayıcıda daha hızlı yüklenir). Daha sonra karşılaşabileceğiniz gibi, derleme sistemindeki bir şey olması gerektiği gibi çalışmadığında incelenmesi gereken dosya budur. Ayrıca, uygulamayı dağıtmak istediğinizde bu, düzenlenmesi gereken önemli dosyalardan biridir (daha fazlasını buradan okuyun).
  • index.html
    Bu HTML dosyası, veri ve kodun dinamik olarak gömüleceği (Vue'nun öncelikli olarak yaptığı şey) matris (veya diyebilirsiniz, şablon) görevi görür ve ardından kullanıcıya sunulur.
  • kaynak/main.js
    Bu JavaScript dosyası, öncelikle üst/proje düzeyindeki bağımlılıkları yöneten ve en üst düzey Vue bileşenini tanımlayan kodu içerir. Kısacası, tüm proje için JavaScript'i düzenler ve uygulamanın giriş noktası olarak hizmet eder. Belirli düğüm modüllerinde proje çapında bağımlılıklar bildirmeniz gerektiğinde veya projedeki en üstteki Vue bileşeni hakkında bir şeylerin değiştirilmesini istediğinizde bu dosyayı düzenleyin.
  • kaynak/App.vue
    Bir önceki noktada “en üstteki Vue bileşeninden” bahsederken aslında bu dosyadan bahsediyorduk. Projedeki her .vue dosyası bir bileşendir ve bileşenler hiyerarşik olarak ilişkilidir. Başlangıçta, tek bileşenimiz olarak yalnızca bir .vue dosyamız var, yani App.vue . Ancak kısa süre sonra projemize daha fazla bileşen ekleyeceğiz (öncelikle gösterge tablosunun yapısını izleyerek) ve bunları, App.vue'nin hepsinin atası olmak üzere, istediğimiz hiyerarşiye göre bağlayacağız. Bu .vue dosyaları, Vue'nun yazmamızı istediği biçimde kod içerecektir. Endişelenmeyin, bizi aklı başında ve düzenli tutabilecek bir yapıyı koruyarak yazılmış JavaScript kodlarıdır. Uyarıldınız — bu projenin sonunda, template — script — style template — script — style kodu düzenlemenin template — script — style yolu!

Artık temeli oluşturduğumuza göre, sıra:

  • Şablonları değiştirin ve yapılandırma dosyalarında biraz ince ayar yapın, böylece proje tam istediğimiz gibi davransın.
  • Yeni .vue dosyaları oluşturun ve gösterge tablosu yapısını Vue koduyla uygulayın.

Biraz uzun olacak ve biraz dikkat gerektiren bir sonraki bölümde bunları öğreneceğiz. Kafein veya suya ihtiyacınız varsa veya deşarj olmak istiyorsanız - şimdi tam zamanı!

3. Varsayılan Proje Yapısını Özelleştirme

İskele projesinin bize verdiği temeli düzeltmenin zamanı geldi. Başlamadan önce, webpack tarafından sağlanan geliştirme sunucusunun çalıştığından emin olun. Bu sunucuyu sürekli çalıştırmanın avantajı, kaynak kodda yaptığınız herhangi bir değişikliğin (birini kaydedip web sayfasını yenilediğiniz) hemen tarayıcıya yansıtılmasıdır.

Geliştirme sunucusunu başlatmak istiyorsanız, terminalden aşağıdaki komutu çalıştırmanız yeterlidir (geçerli dizininizin proje dizini olduğunu varsayarak):

 npm run dev

İlerleyen bölümlerde mevcut dosyalardan bazılarını değiştireceğiz ve bazı yeni dosyalar ekleyeceğiz. Bunu, bu dosyaların içeriğinin kısa açıklamaları izleyecek, böylece bu değişikliklerin ne anlama geldiği hakkında bir fikriniz olacak.

Mevcut Dosyaları Değiştir

index.html

Tarayıcıda görüntülenen tek bir web sayfası olduğundan, uygulamamız kelimenin tam anlamıyla tek sayfalık bir uygulamadır. Bunu daha sonra konuşacağız, ama önce ilk değişikliğimizi yapalım - <title> etiketi içindeki metni değiştirelim.

Bu küçük revizyonla HTML dosyası aşağıdaki gibi görünür:

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <!-- Modify the text of the title tag below --> <title>Vue Weather Dashboard</title> </head> <body> <div></div> <script src="/dist/build.js"></script> </body> </html>

localhost:8080 adresindeki web sayfasını yenilemek için bir dakikanızı ayırın ve tarayıcıdaki sekmenin başlık çubuğuna yansıyan değişikliği görün - "Vue Weather Dashboard" yazmalıdır. Ancak, bu sadece size değişiklik yapma ve çalışıp çalışmadığını doğrulama sürecini göstermek içindi. Yapacak daha çok şeyimiz var!

Bu basit HTML sayfası, projemizde istediğimiz birçok şeyden yoksun, özellikle aşağıdakiler:

  • Bazı meta bilgiler
  • Bootstrap'e CDN bağlantıları (CSS çerçevesi)
  • özel stil sayfasına bağlantı (henüz projeye eklenmemiş)
  • <script> etiketinden Google Haritalar Coğrafi Konum API'sine yönelik işaretçiler

Bunları ekledikten sonra, son index.html aşağıdaki içeriğe sahiptir:

 <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="src/css/style.css"> <title>Weather Dashboard</title> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyC-lCjpg1xbw-nsCc11Si8Ldg2LKYizqI4&libraries=places"></script> </head> <body> <div></div> <script src="/dist/build.js"></script> </body> </html>

Dosyayı kaydedin ve web sayfasını yenileyin. Sayfa yüklenirken hafif bir çıkıntı fark etmiş olabilirsiniz - bunun başlıca nedeni, sayfa stilinin artık Bootstrap tarafından kontrol edilmesi ve yazı tipleri, boşluk vb. gibi stil öğelerinin sahip olduğumuz varsayılandan farklı olmasıdır. daha önce (emin değilseniz, varsayılana dönün ve farkı görün).

Web sayfasını localhost:8080 ile yenilediğinizde bir ekran görüntüsü
(Büyük önizleme)

Not : Devam etmeden önce önemli bir şey var: Google Haritalar API'sinin URL'si, FusionCharts'ın bir özelliği olan bir anahtar içerir. Şimdilik bu anahtarı projeyi oluşturmak için kullanabilirsiniz, çünkü bu tür küçük ayrıntılara takılıp kalmanızı istemiyoruz (bu, yeniyken dikkatinizi dağıtabilir). Ancak, biraz ilerleme kaydettikten ve bu küçük ayrıntılara dikkat etme konusunda kendinizi rahat hissettiğinizde, kendi Google Haritalar API anahtarınızı oluşturmanızı ve kullanmanızı şiddetle tavsiye ederiz.

paket.json

Bunu yazarken, projemiz için npm paketlerinin belirli sürümlerini kullandık ve bunların birlikte çalıştığından eminiz. Ancak, projeyi yürüttüğünüz zaman, npm'nin sizin için indirdiği paketlerin en son kararlı sürümlerinin bizim kullandığımızla aynı olmaması ve bu, kodu kırabilir (veya bunun ötesinde şeyler yapabilir). bizim kontrolümüz). Bu nedenle, kodumuzun/açıklamalarımızın ve elde ettiğiniz sonuçların tutarlı olması için bu projeyi oluşturmak için kullanılan package.json dosyasının tam olarak aynısına sahip olmak çok önemlidir.

package.json dosyasının içeriği şöyle olmalıdır:

 { "name": "vue_weather_dashboard", "description": "A Vue.js project", "version": "1.0.0", "author": "FusionCharts", "license": "MIT", "private": true, "scripts": { "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", "build": "cross-env NODE_ENV=production webpack --progress --hide-modules" }, "dependencies": { "axios": "^0.18.0", "babel": "^6.23.0", "babel-cli": "^6.26.0", "babel-polyfill": "^6.26.0", "fusioncharts": "^3.13.3", "moment": "^2.22.2", "moment-timezone": "^0.5.21", "vue": "^2.5.11", "vue-fusioncharts": "^2.0.4" }, "browserslist": [ "> 1%", "last 2 versions", "not ie <= 8" ], "devDependencies": { "babel-core": "^6.26.0", "babel-loader": "^7.1.2", "babel-preset-env": "^1.6.0", "babel-preset-stage-3": "^6.24.1", "cross-env": "^5.0.5", "css-loader": "^0.28.7", "file-loader": "^1.1.4", "vue-loader": "^13.0.5", "vue-template-compiler": "^2.4.4", "webpack": "^3.6.0", "webpack-dev-server": "^2.9.1" } }

Yeni package.json incelemenizi ve json'daki farklı nesnelerin işlevlerinin neler olduğunu bulmanızı öneririz. Adınıza " author " anahtarının değerini değiştirmeyi tercih edebilirsiniz. Ayrıca, bağımlılıklarda belirtilen paketler, kodda doğru zamanda kendilerini gösterecektir. Şu an için şunu bilmek yeterli:

  • babel ile ilgili paketler, tarayıcı tarafından ES6 stil kodunun düzgün bir şekilde işlenmesi içindir;
  • axios , Promise tabanlı HTTP istekleriyle ilgilenir;
  • moment ve an-zaman dilimi tarih/saat manipülasyonu içindir;
  • fusioncharts ve vue-fusioncharts , çizelgeleri oluşturmaktan sorumludur:
  • vue , bariz nedenlerle.

webpack.config.js

package.json olduğu gibi, projeyi oluşturmak için kullandığımızla tutarlı bir webpack.config.js dosyası tutmanızı öneririz. Ancak, herhangi bir değişiklik yapmadan önce, webpack.config.js içindeki varsayılan kod ile aşağıda verdiğimiz kodu dikkatlice karşılaştırmanızı öneririz. Oldukça az fark göreceksiniz - onları google'da arayın ve ne anlama geldikleri hakkında temel bir fikriniz olsun. Web paketi yapılandırmalarını derinlemesine açıklamak bu makalenin kapsamı dışında olduğundan, bu konuda kendi başınızasınız.

Özelleştirilmiş webpack.config.js dosyası aşağıdaki gibidir:

 var path = require('path') var webpack = require('webpack') module.exports = { entry: ['babel-polyfill', './src/main.js'], output: { path: path.resolve(__dirname, './dist'), publicPath: '/dist/', filename: 'build.js' }, module: { rules: [ { test: /\.css$/, use: [ 'vue-style-loader', 'css-loader' ], }, { test: /\.vue$/, loader: 'vue-loader', options: { loaders: { } // other vue-loader options go here } }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.(png|jpg|gif|svg)$/, loader: 'file-loader', options: { name: '[name].[ext]?[hash]' } } ] }, resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' }, extensions: ['*', '.js', '.vue', '.json'] }, devServer: { historyApiFallback: true, noInfo: true, overlay: true, host: '0.0.0.0', port: 8080 }, performance: { hints: false }, devtool: '#eval-source-map' } if (process.env.NODE_ENV === 'production') { module.exports.devtool = '#source-map' // https://vue-loader.vuejs.org/en/workflow/production.html module.exports.plugins = (module.exports.plugins || []).concat([ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), new webpack.optimize.UglifyJsPlugin({ sourceMap: true, compress: { warnings: false } }), new webpack.LoaderOptionsPlugin({ minimize: true }) ]) }

Projenin webpack.config.js yapılan değişikliklerle, çalışmakta olan geliştirme sunucusunu ( Ctrl + C ) durdurmanız ve package.json belirtilen tüm paketleri kurduktan sonra projenin dizininden yürütülen aşağıdaki komutla yeniden başlatmanız zorunludur. package.json dosyası:

 npm install npm run dev

Bununla, konfigürasyonları değiştirme ve doğru paketlerin yerinde olmasını sağlama çilesi sona eriyor. Ancak, bu aynı zamanda biraz uzun ama aynı zamanda çok ödüllendirici olan kod değiştirme ve yazma yolculuğuna da işaret ediyor!

kaynak/main.js

Bu dosya, projenin üst düzey orkestrasyonunun anahtarıdır - burada tanımladığımız şey:

  • En üst düzey bağımlılıklar nelerdir (gerekli en önemli npm paketlerinin nereden alınacağı);
  • Varsa, eklentileri/sarmalayıcıları kullanma konusunda Vue talimatlarıyla birlikte bağımlılıklar nasıl çözülür;
  • Projedeki en üstteki bileşeni yöneten bir Vue örneği: src/App.vue (nodal .vue dosyası).

src/main.js dosyası için hedeflerimize uygun olarak kod şöyle olmalıdır:

 // Import the dependencies and necessary modules import Vue from 'vue'; import App from './App.vue'; import FusionCharts from 'fusioncharts'; import Charts from 'fusioncharts/fusioncharts.charts'; import Widgets from 'fusioncharts/fusioncharts.widgets'; import PowerCharts from 'fusioncharts/fusioncharts.powercharts'; import FusionTheme from 'fusioncharts/themes/fusioncharts.theme.fusion'; import VueFusionCharts from 'vue-fusioncharts'; // Resolve the dependencies Charts(FusionCharts); PowerCharts(FusionCharts); Widgets(FusionCharts); FusionTheme(FusionCharts); // Globally register the components for project-wide use Vue.use(VueFusionCharts, FusionCharts); // Instantiate the Vue instance that controls the application new Vue({ el: '#app', render: h => h(App) })

kaynak/App.vue

Bu, tüm projedeki en önemli dosyalardan biridir ve hiyerarşideki en üstteki bileşeni, yani bir bütün olarak uygulamanın kendisini temsil eder. Projemiz için bu bileşen, daha sonra keşfedeceğimiz tüm ağır kaldırma işlemlerini yapacak. Şimdilik, varsayılan kazan plakasından kurtulmak ve kendimize ait bir şey koymak istiyoruz.

Vue'nun kod düzenleme yönteminde yeniyseniz, .vue dosyalarındaki genel yapı hakkında bir fikir edinmek daha iyi olacaktır. .vue dosyaları üç bölümden oluşur:

  • Şablon
    Bu, sayfanın HTML şablonunun tanımlandığı yerdir. Statik HTML'nin yanı sıra, bu bölüm ayrıca Vue'nun çift küme parantezini {{ }} kullanarak dinamik içeriği gömme yöntemini de içerir.
  • Senaryo
    JavaScript bu bölümü yönetir ve HTML şablonu içinde uygun yerlere gidip oturan dinamik içerik oluşturmaktan sorumludur. Bu bölüm öncelikle dışa aktarılan bir nesnedir ve şunlardan oluşur:
    • Veri
      Bu bir işlevin kendisidir ve genellikle güzel bir veri yapısı içinde kapsüllenmiş bazı istenen verileri döndürür.
    • yöntemler
      Bir veya daha fazla işlev/yöntemden oluşan ve her biri genellikle verileri şu veya bu şekilde işleyen ve ayrıca HTML şablonunun dinamik içeriğini kontrol eden bir nesne.
    • Hesaplanmış
      Yukarıda önemli bir ayrımla tartışılan yöntem nesnesine çok benzer - yöntem nesnesindeki tüm işlevler, bunlardan herhangi biri çağrıldığında yürütülürken, hesaplanan nesne içindeki işlevler çok daha mantıklı davranır ve ancak ve ancak çalıştırılmışsa yürütülür. isminde.
  • stil
    Bu bölüm, sayfanın HTML'si için geçerli olan CSS stili içindir (şablon içinde yazılmıştır) — sayfalarınızı güzelleştirmek için eski güzel CSS'yi buraya koyun!

Yukarıdaki paradigmayı akılda tutarak, App.vue içindeki kodu minimal olarak özelleştirelim:

 <template> <div> <p>This component's code is in {{ filename }}</p> </div> </template> <script> export default { data() { return { filename: 'App.vue' } }, methods: { }, computed: { }, } </script> <style> </style>

Yukarıdaki kod parçacığının yalnızca App.vue kendi kodumuzla çalıştığını test etmek için olduğunu unutmayın. Daha sonra birçok değişiklikten geçecek, ancak önce dosyayı kaydedin ve sayfayı tarayıcıda yenileyin.

Tarayıcının "Bu bileşenin kodu App.vue'da" mesajını içeren ekran görüntüsü
(Büyük önizleme)

Bu noktada, takımlama konusunda biraz yardım almak muhtemelen iyi bir fikirdir. Chrome için Vue geliştirici araçlarına göz atın ve geliştirme için varsayılan tarayıcınız olarak Google Chrome'u kullanmakta fazla sorun yaşamıyorsanız, aracı yükleyin ve biraz oynayın. İşler daha karmaşık hale geldiğinde, daha fazla geliştirme ve hata ayıklama için son derece kullanışlı olacaktır.

Ek Dizinler ve Dosyalar

Bir sonraki adım, projemizin yapısının tamamlanması için ek dosyalar eklemek olacaktır. Aşağıdaki dizinleri ve dosyaları eklerdik:

  • src/css/style.css
  • src/assets/calendar.svgvlocation.svgwindspeed.svgsearch.svgwinddirection.svg
  • src/components/Content.vueHighlights.vueTempVarChart.vueUVIndex.vueVisibility.vueWindStatus.vue

Not : Köprülü .svg dosyalarını projenize kaydedin.

Yukarıda belirtilen dizinleri ve dosyaları oluşturun. Nihai proje yapısı şöyle görünmelidir (varsayılan yapıdan artık gereksiz olan klasörleri ve dosyaları silmeyi unutmayın):

 vue_weather_dashboard/ |--- README.md |--- node_modules/ | |--- ... | |--- ... | |--- [many npm packages we installed] | |--- ... | |--- ... |--- package.json |--- package-lock.json |--- webpack.config.js |--- index.html |--- src/ | |--- App.vue | |--- css/ | | |--- style.css | |--- assets/ | | |--- calendar.svg | | |--- location.svg | | |--- location.svg | | |--- winddirection.svg | | |--- windspeed.svg | |--- main.js | |--- components/ | | |--- Content.vue | | |--- Highlights.vue | | |--- TempVarChart.vue | | |--- UVIndex.vue | | |--- Visibility.vue | | |--- WindStatus.vue

Projenin kök klasöründe .babelrc , .gitignore , .editorconfig vb. gibi başka dosyalar olabilir . Şimdilik onları güvenle görmezden gelebilirsiniz.

Bir sonraki bölümde, yeni eklenen dosyalara minimum içerik ekleyeceğiz ve düzgün çalışıp çalışmadıklarını test edeceğiz.

kaynak/css/style.css

Hemen pek faydası olmayacak olsa da aşağıdaki kodu dosyaya kopyalayın:

 @import url("https://fonts.googleapis.com/css?family=Roboto:300,400,500"); :root { font-size: 62.5%; } body { font-family: Roboto; font-weight: 400; width: 100%; margin: 0; font-size: 1.6rem; } #sidebar { position: relative; display: flex; flex-direction: column; background-image: linear-gradient(-180deg, #80b6db 0%, #7da7e2 100%); } #search { text-align: center; height: 20vh; position: relative; } #location-input { height: 42px; width: 100%; opacity: 1; border: 0; border-radius: 2px; background-color: rgba(255, 255, 255, 0.2); margin-top: 16px; padding-left: 16px; color: #ffffff; font-size: 1.8rem; line-height: 21px; } #location-input:focus { outline: none; } ::placeholder { color: #FFFFFF; opacity: 0.6; } #current-weather { color: #ffffff; font-size: 8rem; line-height: 106px; position: relative; } #current-weather>span { color: #ffffff; font-size: 3.6rem; line-height: 42px; vertical-align: super; opacity: 0.8; top: 15px; position: absolute; } #weather-desc { font-size: 2.0rem; color: #ffffff; font-weight: 500; line-height: 24px; } #possibility { color: #ffffff; font-size: 16px; font-weight: 500; line-height: 19px; } #max-detail, #min-detail { color: #ffffff; font-size: 2.0rem; font-weight: 500; line-height: 24px; } #max-detail>i, #min-detail>i { font-style: normal; height: 13.27px; width: 16.5px; opacity: 0.4; } #max-detail>span, #min-detail>span { color: #ffffff; font-family: Roboto; font-size: 1.2rem; line-height: 10px; vertical-align: super; } #max-summary, #min-summary { opacity: 0.9; color: #ffffff; font-size: 1.4rem; line-height: 16px; margin-top: 2px; opacity: 0.7; } #search-btn { position: absolute; right: 0; top: 16px; padding: 2px; z-index: 999; height: 42px; width: 45px; background-color: rgba(255, 255, 255, 0.2); border: none; } #dashboard-content { text-align: center; height: 100vh; } #date-desc, #location-desc { color: #ffffff; font-size: 1.6rem; font-weight: 500; line-height: 19px; margin-bottom: 15px; } #date-desc>img { top: -3px; position: relative; margin-right: 10px; } #location-desc>img { top: -3px; position: relative; margin-left: 5px; margin-right: 15px; } #location-detail { opacity: 0.7; color: #ffffff; font-size: 1.4rem; line-height: 20px; margin-left: 35px; } .centered { position: fixed; top: 45%; left: 50%; transform: translate(-50%, -50%); } .max-desc { width: 80px; float: left; margin-right: 28px; } .temp-max-min { margin-top: 40px } #dashboard-content { background-color: #F7F7F7; } .custom-card { background-color: #FFFFFF !important; border: 0 !important; margin-top: 16px !important; margin-bottom: 20px !important; } .custom-content-card { background-color: #FFFFFF !important; border: 0 !important; margin-top: 16px !important; margin-bottom: 0px !important; } .header-card { height: 50vh; } .content-card { height: 43vh; } .card-divider { margin-top: 0; } .content-header { color: #8786A4; font-size: 1.4rem; line-height: 16px; font-weight: 500; padding: 15px 10px 5px 15px; } .highlights-item { min-height: 37vh; max-height: 38vh; background-color: #FFFFFF; } .card-heading { color: rgb(33, 34, 68); font-size: 1.8rem; font-weight: 500; line-height: 21px; text-align: center; } .card-sub-heading { color: #73748C; font-size: 1.6rem; line-height: 19px; } .card-value { color: #000000; font-size: 1.8rem; line-height: 21px; } span text { font-weight: 500 !important; } hr { padding-top: 1.5px; padding-bottom: 1px; margin-bottom: 0; margin-top: 0; line-height: 0.5px; } @media only screen and (min-width: 768px) { #sidebar { height: 100vh; } #info { position: fixed; bottom: 50px; width: 100%; padding-left: 15px; } .wrapper-right { margin-top: 80px; } } @media only screen and (min-width:1440px) { #sidebar { width: 350px; max-width: 350px; flex: auto; } #dashboard-content { width: calc(100% — 350px); max-width: calc(100% — 350px); flex: auto; } }

kaynak/varlıklar/

Bu dizinde, aşağıda belirtilen .svg dosyalarını indirin ve kaydedin:

  • calendar.svg
  • location.svg
  • search.svg
  • winddirection.svg
  • windspeed.svg

kaynak/bileşenler/Content.vue

Bu, yalnızca hiyerarşiyi sürdürmek için orada bulunan ve esas olarak alt bileşenlerine veri aktaran “aptal bileşen” (yani bir yer tutucu) olarak adlandırdığımız şeydir.

Tüm App.vue dosyasına yazmak için teknik bir çubuk olmadığını unutmayın, ancak iki nedenden dolayı bileşenleri iç içe yerleştirerek kodu bölme yaklaşımını benimsiyoruz:

  • Okunabilirliğe ve sürdürülebilirliğe yardımcı olan temiz kod yazmak;
  • Ekranda göreceğimiz yapının aynısını yani hiyerarşiyi çoğaltmak için.

Content.vue içinde tanımlanan bileşeni App.vue kök bileşeni içine yerleştirmeden önce, Content.vue için oyuncak (ama eğitici) bir kod yazalım:

 <template> <div> <p>This child components of Content.vue are:</p> <ul> <li v-for="child in childComponents">{{ child }}</li> </ul> </div> </template> <script> export default { data () { return { childComponents: ['TempVarChart.vue', 'Highlights.vue'] } }, methods: { }, computed: { }, } </script> <style> </style>

Kodda, aşağıdakileri dikkatlice gözlemleyin ve anlayın:

  • <script> etiketi içinde (belli ki burada bir JavaScript kodu yazıyoruz), varsayılan olarak dışa aktarılan (diğer dosyalara sunulan) bir nesne tanımlarız. Bu nesne, öğeleri, daha fazla iç içe yerleştirilmesi gereken bileşen dosyalarının adları olmak üzere, childComponents adlı bir dizi nesnesini döndüren bir data() işlevi içerir.
  • <template> etiketi içinde (bir HTML şablonu yazdığımız yer), ilgilenilen şey <ul> .
    • Sırasız listede, her liste öğesi, childComponents dizi nesnesinde tanımlandığı gibi amaçlanan alt bileşenlerin adları olmalıdır. Ayrıca, liste otomatik olarak dizinin son elemanına kadar uzanmalıdır. Bir for -loop yazmalıyız gibi görünüyor, değil mi? Bunu, Vue.js tarafından sağlanan v-for yönergesini kullanarak yapıyoruz. v-for yönergesi:
      • <li> etiketinin bir niteliği olarak hareket eder, dizi boyunca yinelenir, yineleyicinin {{ }} parantezleri içinde (liste öğeleri için metni yazdığımız) içinde belirtildiği alt bileşenlerin adlarını oluşturur.

Yukarıdaki kod ve açıklama, betik ve şablonun birbiriyle nasıl ilişkili olduğuna ve Vue.js tarafından sağlanan yönergeleri nasıl kullanabileceğimize ilişkin sonraki anlayışınızın temelini oluşturur.

Oldukça fazla şey öğrendik, ancak tüm bunlardan sonra bile, bileşenleri hiyerarşide sorunsuz bir şekilde bağlamak hakkında öğreneceğimiz bir şey kaldı: verileri ana bileşenden alt bileşenlere aktarmak. Şimdilik, src/App.vue src/components/Content.vue bazı verileri nasıl ileteceğimizi öğrenmemiz gerekiyor, böylece bu projede bileşen yerleştirmenin geri kalanı için aynı teknikleri kullanabiliriz.

Ana bileşenden alt bileşenlere aktarılan veriler kulağa basit gelebilir, ancak şeytan ayrıntıda gizlidir! Aşağıda kısaca açıklandığı gibi, çalışmasını sağlamak için birden fazla adım vardır:

  • Tanımlama ve veriler
    Şimdilik, oynamak için bazı statik veriler istiyoruz - havanın farklı yönleri hakkında sabit kodlanmış değerler içeren bir nesne gayet iyi olacak! weather_data adında bir nesne yaratıyoruz ve onu App.vue data() işlevinden döndürüyoruz. weather_data nesnesi aşağıdaki pasajda verilmiştir:
 weather_data: { location: "California", temperature: { current: "35 C", }, highlights: { uvindex: "3", windstatus: { speed: "20 km/h", direction: "NE", }, visibility: "12 km", }, },
  • Verileri ebeveynden geçirme
    Verileri iletmek için verileri göndermek istediğimiz bir hedefe ihtiyacımız var! Bu durumda hedef Content.vue bileşenidir ve bunu uygulamanın yolu şudur:
    • weather_data nesnesini <Content> etiketinin özel özniteliğine atayın
    • Vue.js tarafından sağlanan ve öznitelik değerini dinamik yapan (orijinal verilerde yapılan değişikliklere yanıt veren) v-bind : yönergesini kullanarak özniteliği verilerle bağlayın.
       <Content v-bind:weather_data=“weather_data”></Content>

Verilerin tanımlanması ve iletilmesi, bizim durumumuzda App.vue dosyası olan el sıkışmasının kaynak tarafında işlenir.

App.vue dosyasının mevcut durumundaki kodu aşağıda verilmiştir:

 <template> <div> <p>This component's code is in {{ filename }}</p> <Content v-bind:weather_data="weather_data"></Content> </div> </template> <script> import Content from './components/Content.vue' export default { name: 'app', components: { 'Content': Content }, data () { return { filename: 'App.vue', weather_data: { location: "California", temperature: { current: "35 C", }, highlights: { uvindex: "3", windstatus: { speed: "20 km/h", direction: "NE", }, visibility: "12 km", }, }, } }, methods: { }, computed: { }, } </script> <style> </style> 
"Bu bileşenin kodu App.vue'da. Content.vue'nin bu alt bileşenleri şunlardır: TempVarChart.vue, Highlights.vue”
(Büyük önizleme)

Kaynaktan (ana bileşen) tanımlanan ve geçirilen verilerle, sonraki iki adımda açıklandığı gibi verileri almak ve uygun şekilde oluşturmak artık çocuğun sorumluluğundadır.

  • Verilerin çocuk tarafından alınması
    Alt bileşen, bu durumda Content.vue , ana bileşen App.vue tarafından kendisine gönderilen weather_data nesnesini almalıdır. Vue.js bunu yapmak için bir mekanizma sağlar — tek ihtiyacınız olan, Content.vue tarafından dışa aktarılan varsayılan nesnede tanımlanan props adlı bir dizi nesnesidir. props dizisinin her elemanı, ebeveyninden almak istediği veri nesnelerinin bir adıdır. Şimdilik, alması gereken tek veri nesnesi weather_data weather_data. Böylece props dizisi şöyle görünür:
 <template> // HTML template code here </template> <script> export default { props: ["weather_data"], data () { return { // data here } }, } </script> <style> // component specific CSS here </style>
  • Sayfadaki verileri işleme
    Artık verileri almayı sağladığımıza göre, tamamlamamız gereken son görev verileri işlemek. Bu örnek için, sadece tekniği göstermek için alınan verileri doğrudan web sayfasına dökeceğiz. Ancak, gerçek uygulamalarda (geliştirmek üzere olduğumuz gibi), veriler normalde birçok işlemden geçer ve yalnızca ilgili kısımları amaca uygun şekillerde görüntülenir. Örneğin, bu projede en sonunda hava durumu API'sinden ham verileri alacağız, temizleyeceğiz ve biçimlendireceğiz, verileri grafikler için gerekli veri yapılarına besleyeceğiz ve ardından görselleştireceğiz. Her neyse, ham veri dökümünü görüntülemek için, aşağıdaki pasajda gösterildiği gibi, Vue'nin anladığı {{ }} parantezlerini kullanacağız:
 <template> <div> // other template code here {{ weather_data }} </div> </template>

Şimdi tüm parçaları ve parçaları özümseme zamanı. Content.vue kodu - şu anki durumunda - aşağıda verilmiştir:

 <template> <div> <p>This child components of Content.vue are:</p> <ul> <li v-for="child in childComponents">{{ child }}</li> </ul> {{ weather_data }} </div> </template> <script> export default { props: ["weather_data"], data () { return { childComponents: ['TempVarChart.vue', 'Highlights.vue'] } }, methods: { }, computed: { }, } </script> <style> #pagecontent { border: 1px solid black; padding: 2px; } </style> 
Sağlanan kodun sonucuyla birlikte tarayıcının ekran görüntüsü
(Büyük önizleme)

Yukarıda tartışılan değişiklikleri yaptıktan sonra, web sayfasını tarayıcıda yenileyin ve nasıl göründüğüne bakın. Vue'nun ele aldığı karmaşıklığı takdir etmek için bir dakikanızı ayırın - App.vue içindeki weather_data nesnesini değiştirirseniz, sessizce Content.vue App.vue ve sonunda web sayfasını görüntüleyen tarayıcıya iletilir! Anahtar konumun değerini değiştirerek deneyin.

Statik verileri kullanarak sahne ve veri bağlama hakkında bilgi sahibi olmamıza rağmen, uygulamada web API'leri kullanılarak toplanan dinamik verileri kullanacağız ve kodu buna göre değiştireceğiz .

Özet

.vue dosyalarının geri kalanına geçmeden önce, App.vue ve components/Content.vue kodunu yazarken öğrendiklerimizi özetleyelim:

  • App.vue dosyası, bileşen hiyerarşisinin en üstünde yer alan kök bileşen olarak adlandırdığımız dosyadır. .vue dosyalarının geri kalanı, doğrudan alt öğesi, torunu vb. bileşenleri temsil eder.
  • Content.vue dosyası boş bir bileşendir - sorumluluğu, verileri aşağıdaki düzeylere aktarmak ve yapısal hiyerarşiyi sürdürmektir, böylece kodumuz "*ne görüyorsak onu uygularız*" felsefesiyle tutarlı kalır.
  • Bileşenin ebeveyn-alt ilişkisi yoktan var olmaz — bir bileşeni kaydetmeniz gerekir (bileşenin kullanım amacına bağlı olarak küresel veya yerel olarak) ve ardından onu özel HTML etiketlerini (yazımları tam olarak olan) kullanarak iç içe yerleştirmeniz gerekir. bileşenlerin kayıtlı olduğu adlarla aynı).
  • Kaydedildikten ve iç içe yerleştirildikten sonra, veriler üst bileşenden alt bileşenlere iletilir ve akış asla tersine çevrilmez (proje mimarisi geri akışa izin verirse kötü şeyler olur). Ana bileşen, verilerin göreli kaynağıdır ve özel HTML öğelerinin öznitelikleri için v-bind yönergesini kullanarak ilgili verileri alt öğelerine aktarır. Çocuk, kendisi için amaçlanan verileri sahne kullanarak alır ve ardından verilerle ne yapacağına kendi başına karar verir.

Bileşenlerin geri kalanı için ayrıntılı açıklamalara girmeyeceğiz - sadece yukarıdaki özetten öğrendiklerimize dayanarak kodu yazacağız. Kod aşikar olacaktır ve hiyerarşi konusunda kafanız karışırsa aşağıdaki şemaya bakın:

Kodun hiyerarşisini açıklayan bir diyagram
(Büyük önizleme)

Diyagram, TempVarChart.vue ve Highlights.vue öğelerinin Content.vue öğesinin doğrudan çocuğu olduğunu söylüyor. Bu nedenle, aşağıdaki kodu kullanarak yaptığımız bu bileşenlere veri göndermek için Content.vue hazırlamak iyi bir fikir olabilir:

 <template> <div> <p>This child components of Content.vue are:</p> <ul> <li v-for="child in childComponents">{{ child }}</li> </ul> {{ weather_data }} <temp-var-chart :tempVar="tempVar"></temp-var-chart> <today-highlights :highlights="highlights"></today-highlights> </div> </template> <script> import TempVarChart from './TempVarChart.vue' import Highlights from './Highlights.vue' export default { props: ["weather_data"], components: { 'temp-var-chart': TempVarChart, 'today-highlights': Highlights }, data () { return { childComponents: ['TempVarChart.vue', 'Highlights.vue'], tempVar: this.weather_data.temperature, highlights: this.weather_data.highlights, } }, methods: { }, computed: { }, } </script> <style> </style>

Bu kodu kaydettikten sonra hatalar alacaksınız - endişelenmeyin, bekleniyor. Bileşen dosyalarının geri kalanını hazır hale getirdiğinizde bu sorun çözülecektir. Çıktıyı görememek sizi rahatsız ediyorsa, <temp-var-chart> ve <today-highlights> özel öğe etiketlerini içeren satırları yorumlayın.

Bu bölüm için bu, Content.vue son kodudur. Bu bölümün geri kalanında, bu koda atıfta bulunacağız ve daha önce öğrenmek için yazdığımız kodlara değil.

kaynak/bileşenler/TempVarChart.vue

Üst bileşeni Content.vue verileri aktarırken, TempVarChart.vue , aşağıdaki kodda gösterildiği gibi verileri alacak ve işleyecek şekilde ayarlanmalıdır:

 <template> <div> <p>Temperature Information:</p> {{ tempVar }} </div> </template> <script> export default { props: ["tempVar"], data () { return { } }, methods: { }, computed: { }, } </script> <style> </style>

kaynak/bileşenler/vurgular.vue

Bu bileşen ayrıca, ana bileşeni olan App.vue veri alacaktır. Bundan sonra, alt bileşenleriyle ilişkilendirilmeli ve ilgili veriler onlara aktarılmalıdır.

Önce ebeveynden veri alma kodunu görelim:

 <template> <div> <p>Weather Highlights:</p> {{ highlights }} </div> </template> <script> export default { props: ["highlights"], data () { return { } }, methods: { }, computed: { }, } </script> <style> </style>

Bu noktada, web sayfası aşağıdaki resme benziyor:

Tarayıcıda görüntülenen kodun sonucu
(Büyük önizleme)

Şimdi, alt bileşenlerini kaydetmek ve yerleştirmek için Highlights.vue kodunu değiştirmemiz ve ardından verileri çocuklara aktarmamız gerekiyor. Bunun için kod aşağıdaki gibidir:

 <template> <div> <p>Weather Highlights:</p> {{ highlights }} <uv-index :highlights="highlights"></uv-index> <visibility :highlights="highlights"></visibility> <wind-status :highlights="highlights"></wind-status> </div> </template> <script> import UVIndex from './UVIndex.vue'; import Visibility from './Visibility.vue'; import WindStatus from './WindStatus.vue'; export default { props: ["highlights"], components: { 'uv-index': UVIndex, 'visibility': Visibility, 'wind-status': WindStatus, }, data () { return { } }, methods: { }, computed: { }, } </script> <style> </style>

Kodu kaydedip web sayfasını gördüğünüzde, tarayıcı tarafından sağlanan Developer Console aracında hatalar görmeniz beklenir ; görünürler çünkü Highlights.vue veri gönderiyor olsa da, kimse onları almıyor. Highlights.vue çocukları için henüz kod yazmadık.

Veri işlemenin çoğunu yapmadığımızı, yani gösterge tablosunun Öne Çıkanlar bölümünün altında yer alan hava durumu verilerinin tek tek faktörlerini çıkarmadığımızı gözlemleyin. Bunu data() işlevinde yapabilirdik, ancak Highlights.vue yalnızca aldığı tüm veri dökümünü çocukların her birine ileten aptal bir bileşen olarak tutmayı tercih ettik, daha sonra onlar için gerekli olanı kendi özüne sahip olan çocuklar. . Ancak, Highlights.vue dosyasından veri çıkarmayı denemenizi ve ilgili verileri her alt bileşene göndermenizi öneririz - yine de bu iyi bir uygulama alıştırmasıdır!

kaynak/bileşenler/UVindex.vue

Bu bileşenin kodu, Highlights.vue öne çıkanların veri dökümünü alır, UV İndeksi için verileri çıkarır ve sayfada işler.

 <template> <div> <p>UV Index: {{ uvindex }}</p> </div> </template> <script> export default { props: ["highlights"], data () { return { uvindex: this.highlights.uvindex } }, methods: { }, computed: { }, } </script> <style> </style>

kaynak/bileşenler/Visibility.vue

Bu bileşenin kodu, Highlights.vue öne çıkanların veri dökümünü alır, Görünürlük için verileri çıkarır ve sayfada işler.

 <template> <div> <p>Visibility: {{ visibility }}</p> </div> </template> <script> export default { props: ["highlights"], data () { return { visibility: this.highlights.visibility, } }, methods: { }, computed: { }, } </script> <style> </style>

kaynak/bileşenler/WindStatus.vue

Bu bileşenin kodu, Highlights.vue öne çıkanların veri dökümünü alır, Rüzgar Durumu (hız ve yön) için verileri çıkarır ve sayfada işler.

 <template> <div> <p>Wind Status:</p> <p>Speed — {{ speed }}; Direction — {{ direction }}</p> </div> </template> <script> export default { props: ["highlights"], data () { return { speed: this.highlights.windstatus.speed, direction: this.highlights.windstatus.direction } }, methods: { }, computed: { }, } </script> <style> </style>

Tüm bileşenlerin kodunu ekledikten sonra tarayıcıdan web sayfasına bir göz atın.

Tarayıcıda görüntülenen kodun sonucu
(Büyük önizleme)

Üzülmek için değil, tüm bu uğraşlar sadece bileşenleri hiyerarşik olarak birbirine bağlamak ve aralarında veri akışının olup olmadığını test etmek içindi! Bir sonraki bölümde, şimdiye kadar yazdığımız kodların çoğunu atacağız ve asıl projeyle ilgili daha fazlasını ekleyeceğiz. Ancak, bileşenlerin yapısını ve iç içe yerleşimini kesinlikle koruyacağız; Bu bölümden öğrenilenler, Vue.js ile düzgün bir gösterge panosu oluşturmamıza olanak sağlayacaktır.

4. Veri Toplama ve İşleme

weather_data nesnesini App.vue musunuz? Tüm bileşenlerin doğru çalışıp çalışmadığını test etmek ve ayrıca gerçek dünya verilerinin ayrıntılarında boğulmadan Vue uygulamasının bazı temel yönlerini öğrenmenize yardımcı olmak için kullandığımız bazı sabit kodlanmış veriler vardı. Ancak, artık kabuğumuzdan sıyrılmanın ve API'den gelen verilerin kodumuzun çoğuna hakim olacağı gerçek dünyaya adım atmamızın zamanı geldi.

Alt Bileşenleri Gerçek Verileri Almak ve İşlemek İçin Hazırlama

Bu bölümde, App.vue dışındaki tüm bileşenler için kod dökümü alacaksınız. Kod, App.vue gerçek veri almayı işleyecektir (önceki bölümde sahte veri almak ve işlemek için yazdığımız kodun aksine).

Bu bileşenlerin her birinin beklediği ve sonunda görselleştirmede kullanacağı veriler hakkında bir fikir edinebilmeniz için her bileşenin kodunu dikkatlice okumanızı şiddetle tavsiye ederiz.

Kodun bir kısmı ve genel yapı, önceki yapıda gördüklerinize benzer olacak - bu nedenle büyük ölçüde farklı bir şeyle karşılaşmayacaksınız. Ancak şeytan ayrıntıda gizlidir! Bu yüzden kodu dikkatlice inceleyin ve makul ölçüde iyi anladığınızda, kodu projenizdeki ilgili bileşen dosyalarına kopyalayın.

Not : Bu bölümdeki tüm src/components/ dizinindedir. Bu nedenle, her seferinde yoldan bahsedilmeyecek - bileşeni tanımlamak için yalnızca .vue dosya adından bahsedilecektir.

içerik.vue

 <template> <div> <temp-var-chart :tempVar="tempVar"></temp-var-chart> <today-highlights :highlights="highlights"></today-highlights> </div> </template> <script> import TempVarChart from './TempVarChart.vue'; import Highlights from './Highlights.vue'; export default { props: ['highlights', 'tempVar'], components: { 'temp-var-chart': TempVarChart, 'today-highlights': Highlights }, } </script>

Önceki koddan aşağıdaki değişiklikler yapılmıştır:

  • <template> 'de, {{ }} içindeki metin ve veriler kaldırıldı, çünkü şu anda sadece veri alıyoruz ve bu bileşene özel bir işleme olmaksızın çocuklara aktarıyoruz.
  • export default {} :
    • App.vue props Sahne öğelerini değiştirmenin nedeni, App.vue kendisinin hava durumu API'sinden ve diğer çevrimiçi kaynaklardan elde ettiği verilerin bir kısmını, kullanıcının arama sorgusuna dayalı olarak görüntülemesi ve verilerin geri kalanını iletmesidir. Daha önce yazdığımız kukla kodda, App.vue tüm kukla veri dökümünü herhangi bir ayrım yapmadan aktarıyordu ve Content.vue props'ları buna göre kuruldu.
    • Bu bileşende herhangi bir veri işlemesi yapmadığımız için data() işlevi artık hiçbir şey döndürmez.

TempVarChart.vue

Bu bileşenin, mevcut günün geri kalanı için ayrıntılı sıcaklık projeksiyonları alması ve sonunda bunları FusionCharts kullanarak göstermesi gerekiyor. Ancak şimdilik bunları web sayfasında yalnızca metin olarak görüntüleyeceğiz.

 <template> <div> {{ tempVar.tempToday }} </div> </template> <script> export default { props: ["tempVar"], components: {}, data() { return { }; }, methods: { }, }; </script> <style> </style>

Öne Çıkanlar.vue

 <template> <div> <uv-index :highlights="highlights"></uv-index> <visibility :highlights="highlights"></visibility> <wind-status :highlights="highlights"></wind-status> </div> </template> <script> import UVIndex from './UVIndex.vue'; import Visibility from './Visibility.vue'; import WindStatus from './WindStatus.vue'; export default { props: ["highlights"], components: { 'uv-index': UVIndex, 'visibility': Visibility, 'wind-status': WindStatus, }, data () { return { } }, methods: { }, computed: { }, } </script> <style> </style>

Önceki koddan yapılan değişiklikler şunlardır:

  • <template> 'de, {{ }} içindeki metin ve veriler kaldırılmıştır, çünkü bu aptal bir bileşendir, tıpkı Content.vue gibi, tek işi yapısal hiyerarşiyi korurken verileri çocuklara aktarmak olan. Highlights.vue ve Content.vue gibi aptal bileşenlerin, gösterge panosunun görsel yapısı ile yazdığımız kod arasındaki eşliği korumak için var olduğunu unutmayın.

UVIndex.vue

Önceki kodda yapılan değişiklikler aşağıdaki gibidir:

  • <template> ve <style> içinde, div id daha okunaklı olan uvIndex olarak değiştirildi.
  • export default {} , data() işlevi artık değeri, props kullanılarak bileşen tarafından alınan vurgulamalar nesnesinden çıkarılan bir dize nesnesi uvIndex döndürür. Bu uvIndex artık değeri <template> içinde metin olarak görüntülemek için geçici olarak kullanılıyor. Daha sonra bu değeri grafik oluşturmaya uygun veri yapısına ekleyeceğiz.

Görünürlük.vue

 <template> <div> <p>Visibility: {{ visibility }}</p> </div> </template> <script> export default { props: ["highlights"], data () { return { visibility: this.highlights.visibility.toString() } }, methods: { }, computed: { }, } </script> <style> </style>

Bu dosyada (önceki koduna göre) yapılan tek değişiklik, data() işlevi tarafından döndürülen visibility nesnesinin tanımının artık sonunda toString() içermesidir, çünkü üst öğeden alınan değer değişken olacaktır. dizeye dönüştürülmesi gereken nokta numarası.

WindStatus.vue

 <template> <div> <p>Wind Speed — {{ windSpeed }}</p> <p>Wind Direction — {{ derivedWindDirection }}, or {{ windDirection }} degree clockwise with respect to true N as 0 degree.</p> </div> </template> <script> export default { props: ["highlights"], data () { return { windSpeed: this.highlights.windStatus.windSpeed, derivedWindDirection: this.highlights.windStatus.derivedWindDirection, windDirection: this.highlights.windStatus.windDirection } }, methods: { }, computed: { }, } </script> <style> </style>

Önceki kodda yapılan değişiklikler aşağıdaki gibidir:

  • Dosya boyunca, windstatus , okunabilirliği artırmak ve ayrıca App.vue gerçek verilerle sağladığı vurgulanan nesneyle senkronize olması için windStatus olarak yeniden adlandırıldı.
  • Hız ve yön için benzer adlandırma değişiklikleri yapıldı - yenileri windSpeed ​​ve windDirection .
  • derivedWindDirection adlı yeni bir nesne devreye girdi (ayrıca öne çıkanlar paketinde App.vue tarafından sağlandı).

Şimdilik alınan veriler metin olarak işleniyor; daha sonra görselleştirme için gerekli veri yapısına eklenecektir.

Sahte Verilerle Test Etme

Tekrar tekrar sahte verilere başvurmak sizin için biraz sinir bozucu olabilir, ancak bunun arkasında bazı iyi nedenler var:

  • Her bileşenin kodunda birçok değişiklik yaptık ve bu değişikliklerin kodu bozup bozmadığını test etmek iyi bir fikirdir. Başka bir deyişle, artık projenin daha karmaşık kısımlarına geçmek üzere olduğumuza göre, veri akışının sağlam olup olmadığını kontrol etmeliyiz.
  • Çevrimiçi hava durumu API'sinden gelen gerçek veriler çok fazla masaja ihtiyaç duyacaktır ve veri toplama ve işleme kodu ile bileşenlerden düzgün veri akışı kodu arasında geçiş yapmak sizin için çok zor olabilir. Buradaki fikir, karşılaşabileceğimiz hataları daha iyi anlayabilmemiz için karmaşıklığın kuantumunu kontrol altında tutmaktır.

Bu bölümde yaptığımız şey, App.vue bazı json verilerini temel olarak sabit kodlamaktır ve bu veriler yakın gelecekte canlı verilerle değiştirilecektir. Kukla json yapısı ile gerçek veriler için kullanacağımız json yapısı arasında çok fazla benzerlik var. Bu nedenle, gerçek verilerle karşılaştığımızda ondan ne bekleyeceğiniz konusunda size kabaca bir fikir de sağlar.

Ancak, böyle bir projeyi sıfırdan inşa ederken benimsenebilecek ideal yaklaşımdan çok uzak olduğunu kabul ediyoruz. Gerçek dünyada, genellikle gerçek veri kaynağıyla başlayacak, onu evcilleştirmek için ne yapılabileceğini ve yapılması gerektiğini anlamak için onunla biraz oynayacak ve ardından ilgili bilgileri yakalamak için uygun json veri yapısını düşüneceksiniz. Vue.js ve FusionCharts'ı kullanarak bir gösterge panosu oluşturmayı öğrenme hedefinizden daha da uzağa gittiğinden, sizi tüm bu kirli işlerden kasten koruduk.

Şimdi App.vue için yeni koda geçelim:

 <template> <div> <dashboard-content :highlights="highlights" :tempVar="tempVar"></dashboard-content> </div> </template> <script> import Content from './components/Content.vue' export default { name: 'app', components: { 'dashboard-content': Content }, data () { return { tempVar: { tempToday: [ {hour: '11.00 AM', temp: '35'}, {hour: '12.00 PM', temp: '36'}, {hour: '1.00 PM', temp: '37'}, {hour: '2.00 PM', temp: '38'}, {hour: '3.00 PM', temp: '36'}, {hour: '4.00 PM', temp: '35'}, ], }, highlights: { uvIndex: 4, visibility: 10, windStatus: { windSpeed: '30 km/h', windDirection: '30', derivedWindDirection: 'NNE', }, }, } }, methods: { }, computed: { }, } </script> <style> </style>

Kodda önceki sürümüne göre yapılan değişiklikler aşağıdaki gibidir:

  • Alt bileşenin adı pano içeriği olarak değiştirildi ve buna göre <template> içindeki özel HTML öğesi revize edildi. Özel öğeyle daha önce kullandığımız tek bir öznitelik yerine, artık iki özniteliğe ( highlights ve tempVar ) sahip olduğumuzu unutmayın. Buna göre, bu niteliklerle ilişkili veriler de değişti. Burada ilginç olan, v-bind: : veya onun kısa yolunu (burada yaptığımız gibi) özel bir HTML öğesinin birden çok özniteliğiyle kullanabilmemizdir!
  • data() işlevi şimdi (eski weather_data yerine) iki yeni nesneyle birlikte filename nesnesini (daha önce var olan) döndürür: tempVar ve highlights . Json'un yapısı, alt bileşenlerde yazdığımız koda uygundur, böylece ihtiyaç duydukları veri parçalarını dökümlerden çıkarabilirler. Yapılar oldukça açıklayıcıdır ve canlı verilerle ilgilenirken oldukça benzer olmalarını bekleyebilirsiniz. Bununla birlikte, karşılaşacağınız önemli değişiklik, sabit kodlamanın olmamasıdır (belli ki, değil mi) - değerleri varsayılan durum olarak boş bırakacağız ve onlardan alacağımız değerlere göre dinamik olarak güncellemek için kod yazacağız. hava durumu API'si.

Gerçek çıktıyı görmeden bu bölümde çok fazla kod yazdınız. Devam etmeden önce, tarayıcıya bir göz atın (gerekirse sunucuyu npm run dev ile yeniden başlatın) ve başarınızın görkeminin tadını çıkarın. Bu noktada görmeniz gereken web sayfası aşağıdaki görsele benzer:

Tarayıcıda görüntülenen kodun sonucu
(Büyük önizleme)

Veri Toplama ve İşleme Kodu

Bu bölüm, aşağıdakiler için App.vue yazılacak tüm kodla birlikte projenin özü olacak:

  • Kullanıcıdan konum girişi — bir giriş kutusu ve bir harekete geçirici mesaj düğmesi yeterlidir;
  • Çeşitli görevler için yardımcı işlevler; bu işlevler daha sonra bileşen kodunun çeşitli bölümlerinde çağrılacaktır;
  • JavaScript için Google Haritalar API'sinden ayrıntılı coğrafi konum verilerinin alınması;
  • Dark Sky API'sinden ayrıntılı hava durumu verilerinin alınması;
  • Alt bileşenlere aktarılacak olan coğrafi konum ve hava durumu verilerinin biçimlendirilmesi ve işlenmesi.

Aşağıdaki alt bölümler, yukarıdaki noktalarda bizim için ortaya konan görevleri nasıl uygulayabileceğimizi göstermektedir. Bazı istisnalar dışında, çoğu sırayı takip edecektir.

Kullanıcıdan Girdi

Kullanıcı, hava durumu verilerinin görüntülenmesi gereken yerin adını sağladığında eylemin başladığı oldukça açıktır. Bunun gerçekleşmesi için aşağıdakileri uygulamamız gerekir:

  • Konum girmek için bir giriş kutusu;
  • Uygulamamıza kullanıcının konumu girdiğini ve gerisini yapma zamanının geldiğini bildiren bir gönder düğmesi. Enter tuşuna bastıktan sonra işleme başladığında davranışı da uygulayacağız.

Aşağıda gösterdiğimiz kod, App.vue HTML şablon kısmıyla sınırlı olacaktır. Click olaylarıyla ilişkili yöntemin adından bahsedeceğiz ve bunları daha sonra App.vue'daki <script> method nesnesinde tanımlayacağız.

 <div> <input type="text" ref="input" placeholder="Location?" @keyup.enter="organizeAllDetails" > <button @click="organizeAllDetails"> <img src="./assets/Search.svg" width="24" height="24"> </button> </div>

Yukarıdaki snippet'i doğru yere yerleştirmek önemsizdir - bunu size bırakıyoruz. Ancak, snippet'in ilginç kısımları şunlardır:

  • @keyup.enter="organizeAllDetails"
  • @click="organizeAllDetails"

Önceki bölümlerden bildiğiniz gibi @ , Vue'nun bazı olaylarla ilişkilendirilen v-on : yönergesinin kısaltmasıdır. Yeni şey “ organizeAllDetails ” — olaylar gerçekleştiğinde ( Enter'a basmak veya düğmeyi tıklatmak) tetiklenecek olan yöntemden başka bir şey değil. Henüz yöntemi tanımlamadık ve bulmaca bu bölümün sonunda tamamlanmış olacak.

App.vue Tarafından Kontrol Edilen Metin Bilgi Ekranı

Kullanıcı girişi eylemi tetiklediğinde ve API'lerden çok sayıda veri alındığında, kaçınılmaz soruyla karşılaşırız: “Tüm bu verilerle ne yapmalı?”. Açıkçası bazı veri masajları gerekiyor, ancak bu sorumuzu tam olarak yanıtlamıyor! Verilerin nihai kullanımının ne olduğuna veya daha doğrudan, elde edilen ve işlenen verilerin farklı parçalarını alan varlıklar olduğuna karar vermemiz gerekiyor?

App.vue hiyerarşilerine ve amaçlarına göre alt bileşenleri, verilerin büyük bir kısmı için ön saflardaki yarışmacılardır. Bununla birlikte, bu alt bileşenlerin hiçbirine ait olmayan, ancak oldukça bilgilendirici olan ve gösterge tablosunu tamamlayan bazı verilere de sahip olacağız. Onları doğrudan App.vue tarafından kontrol edilen metin bilgileri olarak görüntülersek, verilerin geri kalanı nihayetinde güzel grafikler olarak görüntülenmesi için çocuğa iletilirse, bunlardan iyi bir şekilde yararlanabiliriz.

Bu bağlamı göz önünde bulundurarak, metin verilerini kullanma aşamasını belirleme koduna odaklanalım. Bu noktada, verilerin sonunda gelip oturacağı basit HTML şablonu.

 <div> <div class="wrapper-left"> <div> {{ currentWeather.temp }} <span>°C</span> </div> <div>{{ currentWeather.summary }}</div> <div class="temp-max-min"> <div class="max-desc"> <div> <i>▲</i> {{ currentWeather.todayHighLow.todayTempHigh }} <span>°C</span> </div> <div>at {{ currentWeather.todayHighLow.todayTempHighTime }}</div> </div> <div class="min-desc"> <div> <i>▼</i> {{ currentWeather.todayHighLow.todayTempLow }} <span>°C</span> </div> <div>at {{ currentWeather.todayHighLow.todayTempLowTime }}</div> </div> </div> </div> <div class="wrapper-right"> <div class="date-time-info"> <div> <img src="./assets/calendar.svg" width="20" height="20"> {{ currentWeather.time }} </div> </div> <div class="location-info"> <div> <img src="./assets/location.svg" width="10.83" height="15.83" > {{ currentWeather.full_location }} <div class="mt-1"> Lat: {{ currentWeather.formatted_lat }} <br> Long: {{ currentWeather.formatted_long }} </div> </div> </div> </div> </div>

Yukarıdaki snippet'te aşağıdakileri anlamalısınız:

  • {{ }} içindekiler — bunlar, tarayıcıda işlenmeden önce Vue'nun HTML şablonuna dinamik veri ekleme yöntemidir. Onlarla daha önce karşılaştınız ve yeni veya şaşırtıcı bir şey yok. Bu veri nesnelerinin, App.vue export default() nesnesindeki data() yönteminden kaynaklandığını unutmayın. Gereksinimlerimize göre ayarlayacağımız varsayılan değerlere sahiptirler ve ardından nesneleri gerçek API verileriyle doldurmak için belirli yöntemler yazarlar.

Tarayıcıdaki değişiklikleri görmediğiniz için endişelenmeyin - veriler henüz tanımlanmamıştır ve Vue'nun bilmediği şeyleri oluşturmaması doğaldır. Ancak, veriler ayarlandıktan sonra (ve şimdilik, verileri sabit kodlayarak bile kontrol edebilirsiniz), metin verileri App.vue tarafından kontrol edilecektir.

data() Yöntemi

data() yöntemi, .vue dosyalarındaki özel bir yapıdır — uygulama için çok önemli olan veri nesnelerini içerir ve döndürür. Herhangi bir .vue dosyasındaki <script> bölümünün genel yapısını hatırlayın - kabaca aşağıdakileri içerir:

 <script> // import statements here export default { // name, components, props, etc. data() { return { // the data that is so crucial for the application is defined here. // the data objects will have certain default values chosen by us. // The methods that we define below will manipulate the data. // Since the data is bounded to various attributes and directives, they // will update as and when the values of the data objects change. } }, methods: { // methods (objects whose values are functions) here. // bulk of dynamic stuff (the black magic part) is controlled from here. }, computed: { // computed properties here }, // other objects, as necessary } </script>

Şimdiye kadar, bazı veri nesnelerinin adlarıyla karşılaştınız, ancak çok daha fazlası. Bunların çoğu, her biri hava durumu bilgisi dökümünün farklı bir yönünü işleyen alt bileşenlerle ilgilidir. Aşağıda, bu proje için ihtiyaç duyacağımız tüm data() yöntemi verilmiştir - API'lerden hangi verileri beklediğimiz ve nesnelerin isimlendirmesine dayalı olarak verileri nasıl yaydığımız hakkında adil bir fikriniz olacak.

 data() { return { weatherDetails: false, location: '', // raw location from input lat: '', // raw latitude from google maps api response long: '', // raw longitude from google maps api response completeWeatherApi: '', // weather api string with lat and long rawWeatherData: '', // raw response from weather api currentWeather: { full_location: '', // for full address formatted_lat: '', // for N/S formatted_long: '', // for E/W time: '', temp: '', todayHighLow: { todayTempHigh: '', todayTempHighTime: '', todayTempLow: '', todayTempLowTime: '' }, summary: '', possibility: '' }, tempVar: { tempToday: [ // gets added dynamically by this.getSetHourlyTempInfoToday() ], }, highlights: { uvIndex: '', visibility: '', windStatus: { windSpeed: '', windDirection: '', derivedWindDirection: '' }, } }; },

Gördüğünüz gibi, çoğu durumda varsayılan değer boştur, çünkü bu noktada bu yeterli olacaktır. Veriler işlenmeden veya alt bileşenlere aktarılmadan önce verileri işlemek ve uygun değerlerle doldurmak için yöntemler yazılacaktır.

App.vue'daki yöntemler

.vue dosyaları için, yöntemler genellikle methods { } nesnesinde yuvalanmış anahtarların değerleri olarak yazılır. Birincil rolleri, bileşenin veri nesnelerini manipüle etmektir. Yöntemleri aynı felsefeyi göz önünde bulundurarak App.vue . Ancak, amaçlarına göre App.vue yöntemlerini aşağıdaki kategorilere ayırabiliriz:

  • Fayda yöntemleri
  • Eylem/Olay odaklı yöntemler
  • Veri toplama yöntemleri
  • Veri işleme yöntemleri
  • Üst düzey tutkal yöntemleri

Bunu anlamanız önemlidir - size yöntemleri bir tabakta sunuyoruz çünkü API'lerin nasıl çalıştığını, hangi verileri verdiklerini ve verileri projemizde nasıl kullanmamız gerektiğini zaten anladık. Yöntemleri yoktan var edip verilerle başa çıkmak için gizli kodlar yazmadık. Öğrenme amacıyla, yöntemler ve veriler için kodu özenle okuyup anlamak iyi bir alıştırmadır. Bununla birlikte, sıfırdan inşa etmeniz gereken yeni bir projeyle karşı karşıya kaldığınızda, tüm kirli işleri kendiniz yapmalısınız ve bu, API'lerle - programatik erişimleri ve veri yapılarıyla - verileri sorunsuz bir şekilde yapıştırmadan önce çok fazla deneme yapmak anlamına gelir. projenizin gerektirdiği yapı. Herhangi bir eliniz olmayacak ve sinir bozucu anlar olacak, ancak bunların hepsi bir geliştirici olarak olgunlaşmanın bir parçası.

Aşağıdaki alt bölümlerde, yöntem türlerinin her birini açıklayacağız ve ayrıca o kategoriye ait yöntemlerin uygulanmasını göstereceğiz. Yöntem adları, amaçları hakkında oldukça açıklayıcıdır ve takip etmesi yeterince kolay bulacağınıza inandığımız uygulamaları da öyle. Ancak bundan önce, .vue dosyalarına yazma yöntemlerinin genel şemasını hatırlayın:

 <script> // import statements here export default { // name, components, props, etc. data() { return { // the data that is so crucial for the application is defined here. } }, methods: { // methods (objects whose values are functions) here. // bulk of dynamic stuff (the black magic part) is controlled from here. method_1: function(arg_1) { }, method_2: function(arg_1, arg_2) { }, method_3: function(arg_1) { }, ……. }, computed: { // computed properties here }, // other objects, as necessary } </script>

Fayda Yöntemleri

Yardımcı yöntemler, adından da anlaşılacağı gibi, öncelikli olarak, kenar görevleri için kullanılan tekrarlayan kodu modülerleştirme amacıyla yazılmış yöntemlerdir. Gerektiğinde başka yöntemlerle çağrılır. Aşağıda verilenler, App.vue için yardımcı program yöntemleridir:

 convertToTitleCase: function(str) { str = str.toLowerCase().split(' '); for (var i = 0; i < str.length; i++) { str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1); } return str.join(' '); },
 // To format the “possibility” (of weather) string obtained from the weather API formatPossibility: function(str) { str = str.toLowerCase().split('-'); for (var i = 0; i < str.length; i++) { str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1); } return str.join(' '); },
 // To convert Unix timestamps according to our convenience unixToHuman: function(timezone, timestamp) { /* READ THIS BEFORE JUDGING & DEBUGGING For any location beyond the arctic circle and the antarctic circle, the goddamn weather api does not return certain keys/values in each of this.rawWeatherData.daily.data[some_array_index]. Due to this, console throws up an error. The code is correct, the problem is with the API. May be later on I will add some padding to tackle missing values. */ var moment = require('moment-timezone'); // for handling date & time var decipher = new Date(timestamp * 1000); var human = moment(decipher) .tz(timezone) .format('llll'); var timeArray = human.split(' '); var timeNumeral = timeArray[4]; var timeSuffix = timeArray[5]; var justTime = timeNumeral + ' ' + timeSuffix; var monthDateArray = human.split(','); var monthDate = monthDateArray[1].trim(); return { fullTime: human, onlyTime: justTime, onlyMonthDate: monthDate }; },
 // To convert temperature from fahrenheit to celcius fahToCel: function(tempInFahrenheit) { var tempInCelcius = Math.round((5 / 9) * (tempInFahrenheit — 32)); return tempInCelcius; },
 // To convert the air pressure reading from millibar to kilopascal milibarToKiloPascal: function(pressureInMilibar) { var pressureInKPA = pressureInMilibar * 0.1; return Math.round(pressureInKPA); },
 // To convert distance readings from miles to kilometers mileToKilometer: function(miles) { var kilometer = miles * 1.60934; return Math.round(kilometer); },
 // To format the wind direction based on the angle deriveWindDir: function(windDir) { var wind_directions_array = [ { minVal: 0, maxVal: 30, direction: 'N' }, { minVal: 31, maxVal: 45, direction: 'NNE' }, { minVal: 46, maxVal: 75, direction: 'NE' }, { minVal: 76, maxVal: 90, direction: 'ENE' }, { minVal: 91, maxVal: 120, direction: 'E' }, { minVal: 121, maxVal: 135, direction: 'ESE' }, { minVal: 136, maxVal: 165, direction: 'SE' }, { minVal: 166, maxVal: 180, direction: 'SSE' }, { minVal: 181, maxVal: 210, direction: 'S' }, { minVal: 211, maxVal: 225, direction: 'SSW' }, { minVal: 226, maxVal: 255, direction: 'SW' }, { minVal: 256, maxVal: 270, direction: 'WSW' }, { minVal: 271, maxVal: 300, direction: 'W' }, { minVal: 301, maxVal: 315, direction: 'WNW' }, { minVal: 316, maxVal: 345, direction: 'NW' }, { minVal: 346, maxVal: 360, direction: 'NNW' } ]; var wind_direction = ''; for (var i = 0; i < wind_directions_array.length; i++) { if ( windDir >= wind_directions_array[i].minVal && windDir <= wind_directions_array[i].maxVal ) { wind_direction = wind_directions_array[i].direction; } } return wind_direction; },

Henüz uygulamamış olsak da, yardımcı program yöntemlerini .vue dosyasından çıkarabilir ve ayrı bir JavaScript dosyasına koyabilirsiniz. Tek yapmanız gereken, .vue dosyasındaki komut dosyası bölümünün başlangıcındaki .js dosyasını içe aktarmaktır ve gitmeniz iyi olur. Bu tür bir yaklaşım gerçekten iyi çalışır ve özellikle amaçlarına göre daha iyi gruplanmış birçok yöntemi kullanabileceğiniz büyük uygulamalarda kodu temiz tutar. Bu yaklaşımı, bu makalede listelenen tüm yöntem gruplarına uygulayabilir ve etkinin kendisini görebilirsiniz. Bununla birlikte, burada sunulan kursu izledikten sonra bu alıştırmayı yapmanızı öneririz, böylece tüm parçaların tam bir senkronizasyon içinde çalıştığına dair büyük resmi anlamış olursunuz ve ayrıca bir zamanlar başvurabileceğiniz çalışan bir yazılım parçasına sahip olursunuz. deneme sırasında bozulur.

Eylem/Olay Odaklı Yöntemler

Bu yöntemler genellikle bir olaya karşılık gelen bir işlem yapmamız gerektiğinde yürütülür. Duruma bağlı olarak, olay bir kullanıcı etkileşiminden veya programlı olarak tetiklenebilir. App.vue dosyasında, bu yöntemler yardımcı program yöntemlerinin altında yer alır.

 makeInputEmpty: function() { this.$refs.input.value = ''; },
 makeTempVarTodayEmpty: function() { this.tempVar.tempToday = []; },
 detectEnterKeyPress: function() { var input = this.$refs.input; input.addEventListener('keyup', function(event) { event.preventDefault(); var enterKeyCode = 13; if (event.keyCode === enterKeyCode) { this.setHitEnterKeyTrue(); } }); },
 locationEntered: function() { var input = this.$refs.input; if (input.value === '') { this.location = "New York"; } else { this.location = this.convertToTitleCase(input.value); } this.makeInputEmpty(); this.makeTempVarTodayEmpty(); },

Yukarıdaki kod parçacıklarının bazılarındaki ilginç bir şey, $ref kullanımıdır. Basit bir ifadeyle, Vue'nin onu içeren kod ifadesini, etkilemesi gereken HTML yapısıyla ilişkilendirme yöntemidir (daha fazla bilgi için resmi kılavuzu okuyun). Örneğin, makeInputEmpty() detectEnterKeyPress() giriş kutusunu etkiler, çünkü giriş kutusunun HTML'sinde ref özniteliğinin değerinden input olarak bahsetmiştik.

Veri Toplama Yöntemleri

Projemizde aşağıdaki iki API kullanıyoruz:

  • Google Haritalar Geocoder API'sı
    Bu API, kullanıcının aradığı konumun koordinatlarını almak içindir. Kendiniz için verilen bağlantıdaki belgeleri takip ederek alabileceğiniz bir API anahtarına ihtiyacınız olacak. Şimdilik FusionCharts tarafından kullanılan API anahtarını kullanabilirsiniz ancak bunu kötüye kullanmamanızı ve kendinize ait bir anahtar almanızı rica ederiz. Bu projenin index.html dosyasından JavaScript API'sine başvuruyoruz ve App.vue dosyasındaki kodumuz için onun sağladığı kurucuları kullanacağız.
  • Karanlık Gökyüzü Hava Durumu API'sı
    Bu API, koordinatlara karşılık gelen hava durumu verilerini almak içindir. Ancak, doğrudan kullanmayacağız; FusionCharts'ın sunucularından biri üzerinden yeniden yönlendiren bir URL içine saracağız. Bunun nedeni, bizimki gibi tamamen istemci-uçlu bir uygulamadan API'ye bir GET isteği gönderirseniz, bunun sinir bozucu CORS hatasıyla sonuçlanmasıdır (daha fazla bilgi burada ve burada).

Önemli Not : Google Haritalar ve Dark Sky API'lerini kullandığımız için bu iki API'nin de kendi API anahtarları vardır ve bu yazımızda sizlerle paylaşmış bulunmaktayız. Bu, arka uç uygulamasının baş ağrısından ziyade müşteri tarafındaki gelişmelere odaklanmanıza yardımcı olacaktır. Ancak kendi anahtarlarınızı oluşturmanızı öneririz çünkü API anahtarlarımız limitlerle gelecek ve bu limitleri aşarsa uygulamayı kendi başınıza deneyemeyeceksiniz.

Google Haritalar için API anahtarınızı almak için bu makaleye gidin. Dark Sky API için, API anahtarınızı ve ilgili uç noktalarınızı oluşturmak üzere https://darksky.net/dev adresini ziyaret edin.

Bağlamı göz önünde bulundurarak, projemiz için veri toplama yöntemlerinin uygulamasını görelim.

 getCoordinates: function() { this.locationEntered(); var loc = this.location; var coords; var geocoder = new google.maps.Geocoder(); return new Promise(function(resolve, reject) { geocoder.geocode({ address: loc }, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { this.lat = results[0].geometry.location.lat(); this.long = results[0].geometry.location.lng(); this.full_location = results[0].formatted_address; coords = { lat: this.lat, long: this.long, full_location: this.full_location }; resolve(coords); } else { alert("Oops! Couldn't get data for the location"); } }); }); },
 /* The coordinates that Google Maps Geocoder API returns are way too accurate for our requirements. We need to bring it into shape before passing the coordinates on to the weather API. Although this is a data processing method in its own right, we can't help mentioning it right now, because the data acquisition method for the weather API has dependency on the output of this method. */ setFormatCoordinates: async function() { var coordinates = await this.getCoordinates(); this.lat = coordinates.lat; this.long = coordinates.long; this.currentWeather.full_location = coordinates.full_location; // Remember to beautify lat for N/S if (coordinates.lat > 0) { this.currentWeather.formatted_lat = (Math.round(coordinates.lat * 10000) / 10000).toString() + '°N'; } else if (coordinates.lat < 0) { this.currentWeather.formatted_lat = (-1 * (Math.round(coordinates.lat * 10000) / 10000)).toString() + '°S'; } else { this.currentWeather.formatted_lat = ( Math.round(coordinates.lat * 10000) / 10000 ).toString(); } // Remember to beautify long for N/S if (coordinates.long > 0) { this.currentWeather.formatted_long = (Math.round(coordinates.long * 10000) / 10000).toString() + '°E'; } else if (coordinates.long < 0) { this.currentWeather.formatted_long = (-1 * (Math.round(coordinates.long * 10000) / 10000)).toString() + '°W'; } else { this.currentWeather.formatted_long = ( Math.round(coordinates.long * 10000) / 10000 ).toString(); } },
 /* This method dynamically creates the the correct weather API query URL, based on the formatted latitude and longitude. The complete URL is then fed to the method querying for weather data. Notice that the base URL used in this method (without the coordinates) points towards a FusionCharts server — we must redirect our GET request to the weather API through a server to avoid the CORS error. */ fixWeatherApi: async function() { await this.setFormatCoordinates(); var weatherApi = 'https://csm.fusioncharts.com/files/assets/wb/wb-data.php?src=darksky&lat=' + this.lat + '&long=' + this.long; this.completeWeatherApi = weatherApi; },
 fetchWeatherData: async function() { await this.fixWeatherApi(); var axios = require('axios'); // for handling weather api promise var weatherApiResponse = await axios.get(this.completeWeatherApi); if (weatherApiResponse.status === 200) { this.rawWeatherData = weatherApiResponse.data; } else { alert('Hmm... Seems like our weather experts are busy!'); } },

Through these methods, we have introduced the concept of async-await in our code. If you have been a JavaScript developer for some time now, you must be familiar with the callback hell, which is a direct consequence of the asynchronous way JavaScript is written. ES6 allows us to bypass the cumbersome nested callbacks, and our code becomes much cleaner if we write JavaScript in a synchronous way, using the async-await technique. However, there is a downside. It takes away the speed that asynchronous code gives us, especially for the portions of the code that deals with data being exchanged over the internet. Since this is not a mission-critical application with low latency requirements, and our primary aim is to learn stuff, the clean code is much more preferable over the slightly fast code.

Data Processing Methods

Now that we have the methods that will bring the data to us, we need to prepare the ground for properly receiving and processing the data. Safety nets must be cast, and there should be no spills — data is the new gold (OK, that might be an exaggeration in our context)! Enough with the fuss, let's get to the point.

Technically, the methods we implement in this section are aimed at getting the data out of the acquisition methods and the data objects in App.vue , and sometimes setting the data objects to certain values that suits the purpose.

getTimezone: function() { return this.rawWeatherData.timezone; },
 getSetCurrentTime: function() { var currentTime = this.rawWeatherData.currently.time; var timezone = this.getTimezone(); this.currentWeather.time = this.unixToHuman( timezone, currentTime ).fullTime; },
 getSetSummary: function() { var currentSummary = this.convertToTitleCase( this.rawWeatherData.currently.summary ); if (currentSummary.includes(' And')) { currentSummary = currentSummary.replace(' And', ','); } this.currentWeather.summary = currentSummary; },
 getSetPossibility: function() { var possible = this.formatPossibility(this.rawWeatherData.daily.icon); if (possible.includes(' And')) { possible = possible.replace(' And', ','); } this.currentWeather.possibility = possible; },
 getSetCurrentTemp: function() { var currentTemp = this.rawWeatherData.currently.temperature; this.currentWeather.temp = this.fahToCel(currentTemp); },
 getTodayDetails: function() { return this.rawWeatherData.daily.data[0]; },
 getSetTodayTempHighLowWithTime: function() { var timezone = this.getTimezone(); var todayDetails = this.getTodayDetails(); this.currentWeather.todayHighLow.todayTempHigh = this.fahToCel( todayDetails.temperatureMax ); this.currentWeather.todayHighLow.todayTempHighTime = this.unixToHuman( timezone, todayDetails.temperatureMaxTime ).onlyTime; this.currentWeather.todayHighLow.todayTempLow = this.fahToCel( todayDetails.temperatureMin ); this.currentWeather.todayHighLow.todayTempLowTime = this.unixToHuman( timezone, todayDetails.temperatureMinTime ).onlyTime; },
 getHourlyInfoToday: function() { return this.rawWeatherData.hourly.data; },
 getSetHourlyTempInfoToday: function() { var unixTime = this.rawWeatherData.currently.time; var timezone = this.getTimezone(); var todayMonthDate = this.unixToHuman(timezone, unixTime).onlyMonthDate; var hourlyData = this.getHourlyInfoToday(); for (var i = 0; i < hourlyData.length; i++) { var hourlyTimeAllTypes = this.unixToHuman(timezone, hourlyData[i].time); var hourlyOnlyTime = hourlyTimeAllTypes.onlyTime; var hourlyMonthDate = hourlyTimeAllTypes.onlyMonthDate; if (todayMonthDate === hourlyMonthDate) { var hourlyObject = { hour: '', temp: '' }; hourlyObject.hour = hourlyOnlyTime; hourlyObject.temp = this.fahToCel(hourlyData[i].temperature).toString(); this.tempVar.tempToday.push(hourlyObject); /* Since we are using array.push(), we are just adding elements at the end of the array. Thus, the array is not getting emptied first when a new location is entered. to solve this problem, a method this.makeTempVarTodayEmpty() has been created, and called from this.locationEntered(). */ } } /* To cover the edge case where the local time is between 10 — 12 PM, and therefore there are only two elements in the array this.tempVar.tempToday. We need to add the points for minimum temperature and maximum temperature so that the chart gets generated with atleast four points. */ if (this.tempVar.tempToday.length <= 2) { var minTempObject = { hour: this.currentWeather.todayHighLow.todayTempHighTime, temp: this.currentWeather.todayHighLow.todayTempHigh }; var maxTempObject = { hour: this.currentWeather.todayHighLow.todayTempLowTime, temp: this.currentWeather.todayHighLow.todayTempLow }; /* Typically, lowest temp are at dawn, highest temp is around mid day. Thus we can safely arrange like min, max, temp after 10 PM. */ // array.unshift() adds stuff at the beginning of the array. // the order will be: min, max, 10 PM, 11 PM. this.tempVar.tempToday.unshift(maxTempObject, minTempObject); } },
 getSetUVIndex: function() { var uvIndex = this.rawWeatherData.currently.uvIndex; this.highlights.uvIndex = uvIndex; },
 getSetVisibility: function() { var visibilityInMiles = this.rawWeatherData.currently.visibility; this.highlights.visibility = this.mileToKilometer(visibilityInMiles); },
 getSetWindStatus: function() { var windSpeedInMiles = this.rawWeatherData.currently.windSpeed; this.highlights.windStatus.windSpeed = this.mileToKilometer( windSpeedInMiles ); var absoluteWindDir = this.rawWeatherData.currently.windBearing; this.highlights.windStatus.windDirection = absoluteWindDir; this.highlights.windStatus.derivedWindDirection = this.deriveWindDir( absoluteWindDir ); },

Üst Düzey Tutkal Yöntemleri

Yardımcı program, satın alma ve işleme yöntemlerinin yolumuzdan çekilmesiyle, şimdi her şeyi düzenleme görevi bize kaldı. Bunu, tüm işlemin sorunsuz bir şekilde yürütülmesi için, esasen yukarıda yazılan yöntemleri belirli bir sırayla çağıran yüksek seviyeli yapıştırma yöntemleri oluşturarak yapıyoruz.

 // Top level for info section // Data in this.currentWeather organizeCurrentWeatherInfo: function() { // data in this.currentWeather /* Coordinates and location is covered (get & set) in: — this.getCoordinates() — this.setFormatCoordinates() There are lots of async-await involved there. So it's better to keep them there. */ this.getSetCurrentTime(); this.getSetCurrentTemp(); this.getSetTodayTempHighLowWithTime(); this.getSetSummary(); this.getSetPossibility(); },
 // Top level for highlights organizeTodayHighlights: function() { // top level for highlights this.getSetUVIndex(); this.getSetVisibility(); this.getSetWindStatus(); },
 // Top level organization and rendering organizeAllDetails: async function() { // top level organization await this.fetchWeatherData(); this.organizeCurrentWeatherInfo(); this.organizeTodayHighlights(); this.getSetHourlyTempInfoToday(); },

monte edilmiş

Vue, örnek yaşam döngüsü kancaları sağlar - esasen yöntemler olan ve örnek yaşam döngüsü bu aşamaya ulaştığında tetiklenen özellikler. Örneğin, oluşturulan, monte edilen, BeforeUpdate vb.'nin tümü, programcının örneği, aksi takdirde mümkün olandan çok daha ayrıntılı bir düzeyde kontrol etmesine olanak tanıyan çok kullanışlı yaşam döngüsü kancalarıdır.

Bir Vue bileşeninin kodunda, bu yaşam döngüsü kancaları, tıpkı diğer herhangi bir prop için yaptığınız gibi uygulanır. Örneğin:

 <template> </template> <script> // import statements export default { data() { return { // data objects here } }, methods: { // methods here }, mounted: function(){ // function body here }, } </script> <style> </style>

Bu yeni anlayışla donanmış olarak, App.vue mounted pervanesi için aşağıdaki koda bir göz atın:

 mounted: async function() { this.location = "New York"; await this.organizeAllDetails(); }

App.vue İçin Kodu Tamamlayın

Bu bölümde çok yol kat ettik ve son birkaç bölüm size parça parça şeyler verdi. Ancak, App.vue için eksiksiz, birleştirilmiş koda sahip olmanız önemlidir (sonraki bölümlerde daha fazla değişiklik yapılmasına tabidir). İşte gidiyor:

 <template> <div> <div class="container-fluid"> <div class="row"> <div class="col-md-3 col-sm-4 col-xs-12 sidebar"> <div> <input type="text" ref="input" placeholder="Location?" @keyup.enter="organizeAllDetails" > <button @click="organizeAllDetails"> <img src="./assets/Search.svg" width="24" height="24"> </button> </div> <div> <div class="wrapper-left"> <div> {{ currentWeather.temp }} <span>°C</span> </div> <div>{{ currentWeather.summary }}</div> <div class="temp-max-min"> <div class="max-desc"> <div> <i>▲</i> {{ currentWeather.todayHighLow.todayTempHigh }} <span>°C</span> </div> <div>at {{ currentWeather.todayHighLow.todayTempHighTime }}</div> </div> <div class="min-desc"> <div> <i>▼</i> {{ currentWeather.todayHighLow.todayTempLow }} <span>°C</span> </div> <div>at {{ currentWeather.todayHighLow.todayTempLowTime }}</div> </div> </div> </div> <div class="wrapper-right"> <div class="date-time-info"> <div> <img src="./assets/calendar.svg" width="20" height="20"> {{ currentWeather.time }} </div> </div> <div class="location-info"> <div> <img src="./assets/location.svg" width="10.83" height="15.83" > {{ currentWeather.full_location }} <div class="mt-1"> Lat: {{ currentWeather.formatted_lat }} <br> Long: {{ currentWeather.formatted_long }} </div> </div> </div> </div> </div> </div> <dashboard-content class="col-md-9 col-sm-8 col-xs-12 content" :highlights="highlights" :tempVar="tempVar" ></dashboard-content> </div> </div> </div> </template> <script> import Content from './components/Content.vue'; export default { name: 'app', props: [], components: { 'dashboard-content': Content }, data() { return { weatherDetails: false, location: '', // raw location from input lat: '', // raw latitude from google maps api response long: '', // raw longitude from google maps api response completeWeatherApi: '', // weather api string with lat and long rawWeatherData: '', // raw response from weather api currentWeather: { full_location: '', // for full address formatted_lat: '', // for N/S formatted_long: '', // for E/W time: '', temp: '', todayHighLow: { todayTempHigh: '', todayTempHighTime: '', todayTempLow: '', todayTempLowTime: '' }, summary: '', possibility: '' }, tempVar: { tempToday: [ // gets added dynamically by this.getSetHourlyTempInfoToday() ], }, highlights: { uvIndex: '', visibility: '', windStatus: { windSpeed: '', windDirection: '', derivedWindDirection: '' }, } }; }, methods: { // Some utility functions convertToTitleCase: function(str) { str = str.toLowerCase().split(' '); for (var i = 0; i < str.length; i++) { str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1); } return str.join(' '); }, formatPossibility: function(str) { str = str.toLowerCase().split('-'); for (var i = 0; i < str.length; i++) { str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1); } return str.join(' '); }, unixToHuman: function(timezone, timestamp) { /* READ THIS BEFORE JUDGING & DEBUGGING For any location beyond the arctic circle and the antarctic circle, the goddamn weather api does not return certain keys/values in each of this.rawWeatherData.daily.data[some_array_index]. Due to this, console throws up an error. The code is correct, the problem is with the API. May be later on I will add some padding to tackle missing values. */ var moment = require('moment-timezone'); // for handling date & time var decipher = new Date(timestamp * 1000); var human = moment(decipher) .tz(timezone) .format('llll'); var timeArray = human.split(' '); var timeNumeral = timeArray[4]; var timeSuffix = timeArray[5]; var justTime = timeNumeral + ' ' + timeSuffix; var monthDateArray = human.split(','); var monthDate = monthDateArray[1].trim(); return { fullTime: human, onlyTime: justTime, onlyMonthDate: monthDate }; }, fahToCel: function(tempInFahrenheit) { var tempInCelcius = Math.round((5 / 9) * (tempInFahrenheit — 32)); return tempInCelcius; }, milibarToKiloPascal: function(pressureInMilibar) { var pressureInKPA = pressureInMilibar * 0.1; return Math.round(pressureInKPA); }, mileToKilometer: function(miles) { var kilometer = miles * 1.60934; return Math.round(kilometer); }, deriveWindDir: function(windDir) { var wind_directions_array = [ { minVal: 0, maxVal: 30, direction: 'N' }, { minVal: 31, maxVal: 45, direction: 'NNE' }, { minVal: 46, maxVal: 75, direction: 'NE' }, { minVal: 76, maxVal: 90, direction: 'ENE' }, { minVal: 91, maxVal: 120, direction: 'E' }, { minVal: 121, maxVal: 135, direction: 'ESE' }, { minVal: 136, maxVal: 165, direction: 'SE' }, { minVal: 166, maxVal: 180, direction: 'SSE' }, { minVal: 181, maxVal: 210, direction: 'S' }, { minVal: 211, maxVal: 225, direction: 'SSW' }, { minVal: 226, maxVal: 255, direction: 'SW' }, { minVal: 256, maxVal: 270, direction: 'WSW' }, { minVal: 271, maxVal: 300, direction: 'W' }, { minVal: 301, maxVal: 315, direction: 'WNW' }, { minVal: 316, maxVal: 345, direction: 'NW' }, { minVal: 346, maxVal: 360, direction: 'NNW' } ]; var wind_direction = ''; for (var i = 0; i < wind_directions_array.length; i++) { if ( windDir >= wind_directions_array[i].minVal && windDir <= wind_directions_array[i].maxVal ) { wind_direction = wind_directions_array[i].direction; } } return wind_direction; }, // Some basic action oriented functions makeInputEmpty: function() { this.$refs.input.value = ''; }, makeTempVarTodayEmpty: function() { this.tempVar.tempToday = []; }, detectEnterKeyPress: function() { var input = this.$refs.input; input.addEventListener('keyup', function(event) { event.preventDefault(); var enterKeyCode = 13; if (event.keyCode === enterKeyCode) { this.setHitEnterKeyTrue(); } }); }, locationEntered: function() { var input = this.$refs.input; if (input.value === '') { this.location = "New York"; } else { this.location = this.convertToTitleCase(input.value); } this.makeInputEmpty(); this.makeTempVarTodayEmpty(); }, getCoordinates: function() { this.locationEntered(); var loc = this.location; var coords; var geocoder = new google.maps.Geocoder(); return new Promise(function(resolve, reject) { geocoder.geocode({ address: loc }, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { this.lat = results[0].geometry.location.lat(); this.long = results[0].geometry.location.lng(); this.full_location = results[0].formatted_address; coords = { lat: this.lat, long: this.long, full_location: this.full_location }; resolve(coords); } else { alert("Oops! Couldn't get data for the location"); } }); }); }, // Some basic asynchronous functions setFormatCoordinates: async function() { var coordinates = await this.getCoordinates(); this.lat = coordinates.lat; this.long = coordinates.long; this.currentWeather.full_location = coordinates.full_location; // Remember to beautify lat for N/S if (coordinates.lat > 0) { this.currentWeather.formatted_lat = (Math.round(coordinates.lat * 10000) / 10000).toString() + '°N'; } else if (coordinates.lat < 0) { this.currentWeather.formatted_lat = (-1 * (Math.round(coordinates.lat * 10000) / 10000)).toString() + '°S'; } else { this.currentWeather.formatted_lat = ( Math.round(coordinates.lat * 10000) / 10000 ).toString(); } // Remember to beautify long for N/S if (coordinates.long > 0) { this.currentWeather.formatted_long = (Math.round(coordinates.long * 10000) / 10000).toString() + '°E'; } else if (coordinates.long < 0) { this.currentWeather.formatted_long = (-1 * (Math.round(coordinates.long * 10000) / 10000)).toString() + '°W'; } else { this.currentWeather.formatted_long = ( Math.round(coordinates.long * 10000) / 10000 ).toString(); } }, fixWeatherApi: async function() { await this.setFormatCoordinates(); var weatherApi = 'https://csm.fusioncharts.com/files/assets/wb/wb-data.php?src=darksky&lat=' + this.lat + '&long=' + this.long; this.completeWeatherApi = weatherApi; }, fetchWeatherData: async function() { await this.fixWeatherApi(); var axios = require('axios'); // for handling weather api promise var weatherApiResponse = await axios.get(this.completeWeatherApi); if (weatherApiResponse.status === 200) { this.rawWeatherData = weatherApiResponse.data; } else { alert('Hmm... Seems like our weather experts are busy!'); } }, // Get and set functions; often combined, because they are short // For basic info — left panel/sidebar getTimezone: function() { return this.rawWeatherData.timezone; }, getSetCurrentTime: function() { var currentTime = this.rawWeatherData.currently.time; var timezone = this.getTimezone(); this.currentWeather.time = this.unixToHuman( timezone, currentTime ).fullTime; }, getSetSummary: function() { var currentSummary = this.convertToTitleCase( this.rawWeatherData.currently.summary ); if (currentSummary.includes(' And')) { currentSummary = currentSummary.replace(' And', ','); } this.currentWeather.summary = currentSummary; }, getSetPossibility: function() { var possible = this.formatPossibility(this.rawWeatherData.daily.icon); if (possible.includes(' And')) { possible = possible.replace(' And', ','); } this.currentWeather.possibility = possible; }, getSetCurrentTemp: function() { var currentTemp = this.rawWeatherData.currently.temperature; this.currentWeather.temp = this.fahToCel(currentTemp); }, getTodayDetails: function() { return this.rawWeatherData.daily.data[0]; }, getSetTodayTempHighLowWithTime: function() { var timezone = this.getTimezone(); var todayDetails = this.getTodayDetails(); this.currentWeather.todayHighLow.todayTempHigh = this.fahToCel( todayDetails.temperatureMax ); this.currentWeather.todayHighLow.todayTempHighTime = this.unixToHuman( timezone, todayDetails.temperatureMaxTime ).onlyTime; this.currentWeather.todayHighLow.todayTempLow = this.fahToCel( todayDetails.temperatureMin ); this.currentWeather.todayHighLow.todayTempLowTime = this.unixToHuman( timezone, todayDetails.temperatureMinTime ).onlyTime; }, getHourlyInfoToday: function() { return this.rawWeatherData.hourly.data; }, getSetHourlyTempInfoToday: function() { var unixTime = this.rawWeatherData.currently.time; var timezone = this.getTimezone(); var todayMonthDate = this.unixToHuman(timezone, unixTime).onlyMonthDate; var hourlyData = this.getHourlyInfoToday(); for (var i = 0; i < hourlyData.length; i++) { var hourlyTimeAllTypes = this.unixToHuman(timezone, hourlyData[i].time); var hourlyOnlyTime = hourlyTimeAllTypes.onlyTime; var hourlyMonthDate = hourlyTimeAllTypes.onlyMonthDate; if (todayMonthDate === hourlyMonthDate) { var hourlyObject = { hour: '', temp: '' }; hourlyObject.hour = hourlyOnlyTime; hourlyObject.temp = this.fahToCel(hourlyData[i].temperature).toString(); this.tempVar.tempToday.push(hourlyObject); /* Since we are using array.push(), we are just adding elements at the end of the array. Thus, the array is not getting emptied first when a new location is entered. to solve this problem, a method this.makeTempVarTodayEmpty() has been created, and called from this.locationEntered(). */ } } /* To cover the edge case where the local time is between 10 — 12 PM, and therefore there are only two elements in the array this.tempVar.tempToday. We need to add the points for minimum temperature and maximum temperature so that the chart gets generated with atleast four points. */ if (this.tempVar.tempToday.length <= 2) { var minTempObject = { hour: this.currentWeather.todayHighLow.todayTempHighTime, temp: this.currentWeather.todayHighLow.todayTempHigh }; var maxTempObject = { hour: this.currentWeather.todayHighLow.todayTempLowTime, temp: this.currentWeather.todayHighLow.todayTempLow }; /* Typically, lowest temp are at dawn, highest temp is around mid day. Thus we can safely arrange like min, max, temp after 10 PM. */ // array.unshift() adds stuff at the beginning of the array. // the order will be: min, max, 10 PM, 11 PM. this.tempVar.tempToday.unshift(maxTempObject, minTempObject); } }, // For Today Highlights getSetUVIndex: function() { var uvIndex = this.rawWeatherData.currently.uvIndex; this.highlights.uvIndex = uvIndex; }, getSetVisibility: function() { var visibilityInMiles = this.rawWeatherData.currently.visibility; this.highlights.visibility = this.mileToKilometer(visibilityInMiles); }, getSetWindStatus: function() { var windSpeedInMiles = this.rawWeatherData.currently.windSpeed; this.highlights.windStatus.windSpeed = this.mileToKilometer( windSpeedInMiles ); var absoluteWindDir = this.rawWeatherData.currently.windBearing; this.highlights.windStatus.windDirection = absoluteWindDir; this.highlights.windStatus.derivedWindDirection = this.deriveWindDir( absoluteWindDir ); }, // top level for info section organizeCurrentWeatherInfo: function() { // data in this.currentWeather /* Coordinates and location is covered (get & set) in: — this.getCoordinates() — this.setFormatCoordinates() There are lots of async-await involved there. So it's better to keep them there. */ this.getSetCurrentTime(); this.getSetCurrentTemp(); this.getSetTodayTempHighLowWithTime(); this.getSetSummary(); this.getSetPossibility(); }, organizeTodayHighlights: function() { // top level for highlights this.getSetUVIndex(); this.getSetVisibility(); this.getSetWindStatus(); }, // topmost level orchestration organizeAllDetails: async function() { // top level organization await this.fetchWeatherData(); this.organizeCurrentWeatherInfo(); this.organizeTodayHighlights(); this.getSetHourlyTempInfoToday(); }, }, mounted: async function() { this.location = "New York"; await this.organizeAllDetails(); } }; </script>

Ve son olarak, onca sabır ve sıkı çalışmadan sonra, ham gücüyle veri akışını görebilirsiniz! Tarayıcıda uygulamayı ziyaret edin, sayfayı yenileyin, uygulamanın arama kutusunda bir konum arayın ve Enter'a basın!

Tarayıcıda gösterildiği gibi uygulama
(Büyük önizleme)

Artık tüm ağır kaldırmayı bitirdiğimize göre, bir ara verin. Sonraki bölümler, verileri güzel ve bilgilendirici grafikler oluşturmak için kullanmaya odaklanır, ardından çirkin görünümlü uygulamamıza CSS kullanarak çok hak ettiği bir bakım oturumu verir.

5. FusionCharts ile Veri Görselleştirme

Grafikler İçin Temel Hususlar

Son kullanıcı için, bir gösterge panosunun özü esas olarak şudur: belirli bir konu hakkında filtrelenmiş ve özenle seçilmiş bilgilerin bir koleksiyonu, hızlı alım için görsel/grafik araçlar aracılığıyla aktarılır. Veri hattı mühendisliğinizin inceliklerini veya kodunuzun ne kadar estetik olduğunu umursamıyorlar - tek istedikleri 3 saniye içinde üst düzey bir görünüm. Bu nedenle, metin verilerini görüntüleyen kaba uygulamamız onlar için hiçbir şey ifade etmiyor ve verileri grafiklerle sarmak için mekanizmalar uygulamamızın tam zamanı.

Bununla birlikte, çizelgelerin uygulanmasına derinlemesine dalmadan önce, bazı ilgili soruları ve olası cevapları kendi bakış açımızdan ele alalım:

  • Uğraştığımız veri türü için ne tür grafikler uygundur?
    Cevabın iki yönü var - bağlam ve amaç. Bağlam olarak, veri türünü kastediyoruz ve genel olarak, projenin kapsamı ve hedef kitlesi tarafından sınırlanan daha büyük şeylerin şemasına uyuyor. Ve amaç olarak, esasen “neye vurgu yapmak istiyoruz?” demek istiyoruz. Örneğin, bir Sütun grafiği (yüksekliği sütunun temsil ettiği değerle orantılı, eşit genişlikte dikey sütunlar) kullanarak günün farklı saatlerinde bugünün sıcaklığını temsil edebiliriz. Bununla birlikte, bireysel değerlerle nadiren ilgileniriz, bunun yerine veriler boyunca genel varyasyon ve eğilimle ilgileniriz. Amaca uygun olması için Çizgi grafiği kullanmak bizim yararımızadır ve bunu kısa süre içinde yapacağız.
  • Bir grafik kitaplığı seçmeden önce nelere dikkat edilmelidir?
    Ağırlıklı olarak JavaScript tabanlı teknolojileri kullanan bir proje yaptığımız için, projemiz için seçtiğimiz herhangi bir grafik kitaplığının JavaScript dünyasının yerlisi olması hiç de kolay değil. Bu temel öncülü göz önünde bulundurarak, belirli bir kitaplığı sıfırlamadan önce aşağıdakileri göz önünde bulundurmalıyız:
    • Bu durumda Vue.js olan bizim tercih ettiğimiz çerçeveler için destek. React veya Angular gibi diğer popüler JavaScript çerçevelerinde bir proje geliştirilebilir - favori çerçeveniz için grafik kitaplığının desteğini kontrol edin. Ayrıca, Python, Java, C++, .Net (AS ve VB) gibi diğer popüler programlama dilleri için destek, özellikle proje bazı ciddi arka uç şeyler içerdiğinde düşünülmelidir.
    • Projedeki verilerin nihai şeklinin ve amacının ne olacağını önceden bilmek neredeyse imkansız olduğundan , çizelge türlerinin ve özelliklerinin mevcudiyeti (özellikle gereksinimler müşterileriniz tarafından profesyonel bir ortamda düzenleniyorsa). Bu durumda, ağınızı geniş tutmalı ve en geniş grafik koleksiyonuna sahip bir grafik kitaplığı seçmelisiniz. Daha da önemlisi, projenizi diğerlerinden farklı kılmak için, kitaplığın yapılandırılabilir grafik öznitelikleri biçiminde yeterli özelliklere sahip olması gerekir, böylece çizelgelerin çoğu yönünü ve doğru ayrıntı düzeyini ayarlayabilir ve özelleştirebilirsiniz. Ayrıca, varsayılan grafik yapılandırmaları mantıklı olmalı ve profesyonel geliştiriciler için açık olan nedenlerden dolayı kitaplık belgeleri birinci sınıf olmalıdır.
    • Özellikle veri görselleştirme konusunda yeniyseniz, öğrenme eğrisi, destek topluluğu ve denge de dikkate alınmalıdır. Yelpazenin bir ucunda, bir bombaya mal olan, sorunsuz bir öğrenme eğrisine sahip olan, ancak aynı zamanda özelleştirilebilirlik, entegrasyon ve dağıtım açısından pek çok sınırlama getiren Tableau ve Qlickview gibi tescilli araçlarınız var. Diğer uçta ise d3.js var — geniş, ücretsiz (açık kaynak) ve özüne göre özelleştirilebilir, ancak kitaplıkla üretken bir şey yapabilmek için çok dik bir öğrenme eğrisinin bedelini ödemeniz gerekiyor.

İhtiyacınız olan şey en doğru noktadır - üretkenlik, kapsam, özelleştirilebilirlik, öğrenme eğrisi ve rota dışı maliyet arasında doğru denge. Bu projede grafikler oluşturmak için kullanacağımız, web ve mobil için dünyanın en kapsamlı ve kurumsal kullanıma hazır JavaScript grafik kitaplığı olan FusionCharts'a göz atmanızı rica ediyoruz.

FusionCharts'a Giriş

FusionCharts, dünya çapında yüzlerce ülkeye yayılmış milyonlarca geliştirici tarafından JavaScript grafik kitaplığı olarak kullanılır. Teknik olarak, web tabanlı projeler için kullanılan hemen hemen tüm popüler teknoloji yığınlarıyla entegre etme desteğiyle, olabildiğince yüklü ve yapılandırılabilir. FusionCharts'ı ticari olarak kullanmak bir lisans gerektirir ve kullanım durumunuza bağlı olarak lisans için ödeme yapmanız gerekir (eğer merak ediyorsanız lütfen satış ekibiyle iletişime geçin). Ancak, bu projelerde FusionCharts'ı yalnızca birkaç şeyi denemek için kullanıyoruz ve bu nedenle lisanssız sürüm (grafiklerinizde küçük bir filigran ve birkaç başka kısıtlamayla birlikte gelir). Grafikleri denerken ve ticari olmayan veya kişisel projelerinizde kullanırken lisanssız sürümü kullanmak gayet iyi. Uygulamayı ticari olarak dağıtmayı planlıyorsanız, lütfen FusionCharts'tan bir lisansınız olduğundan emin olun.

Bu, Vue.js'yi içeren bir proje olduğundan, daha önce yapılmadıysa, kurulması gereken iki modüle ihtiyacımız olacak:

  • fusioncharts modülü, çizelgeleri oluşturmak için ihtiyaç duyacağınız her şeyi içerdiğinden
  • Esasen bir Vue.js projesinde kullanılabilmesi için fusioncharts için bir sarmalayıcı olan vue-fusioncharts modülü

Bunları daha önce kurmadıysanız (üçüncü bölümde anlatıldığı gibi), projenin kök dizininden aşağıdaki komutu yürüterek kurun:

 npm install fusioncharts vue-fusioncharts --save

Ardından, projenin src/main.js dosyasının aşağıdaki koda sahip olduğundan emin olun (ayrıca bölüm 3'te de bahsedilmiştir):

 import Vue from 'vue'; import App from './App.vue'; import FusionCharts from 'fusioncharts'; import Charts from 'fusioncharts/fusioncharts.charts'; import Widgets from 'fusioncharts/fusioncharts.widgets'; import PowerCharts from 'fusioncharts/fusioncharts.powercharts'; import FusionTheme from 'fusioncharts/themes/fusioncharts.theme.fusion'; import VueFusionCharts from 'vue-fusioncharts'; Charts(FusionCharts); PowerCharts(FusionCharts); Widgets(FusionCharts); FusionTheme(FusionCharts); Vue.use(VueFusionCharts, FusionCharts); new Vue({ el: '#app', render: h => h(App) })

Yukarıdaki pasajdaki belki de en kritik satır şudur:

 Vue.use(VueFusionCharts, FusionCharts)

Vue'ya, projede açıkça bizim tarafımızdan açıkça tanımlanmayan, ancak modülün kendisinde tanımlanan birçok şeyi anlamlandırmak için vue-fusioncharts modülünü kullanmasını söyler. Ayrıca, bu tür bir ifade küresel bildirim anlamına gelir; bununla Vue'nin projemizin kodunda herhangi bir garip şeyle karşılaştığını (FusionCharts kullanımı hakkında açıkça tanımlamadığımız şeyler), en azından bir kez vue-fusioncharts'a bakacağını kastediyoruz. ve fusioncharts, hataları atmadan önce tanımları için düğüm modülleri. FusionCharts'ı projemizin yalıtılmış bir bölümünde kullansaydık (neredeyse tüm bileşen dosyalarında kullanmazdık), o zaman belki de yerel bildirim daha anlamlı olurdu.

Bununla, projede FusionCharts'ı kullanmaya hazırsınız. Oldukça çeşitli grafikler kullanacağız, seçim, görselleştirmek istediğimiz hava durumu verilerinin yönüne bağlı. Ayrıca, veri bağlama, özel bileşenler ve izleyicilerin etkileşimini çalışırken göreceğiz.

.vue Dosyalarında Fusioncharts Kullanmak İçin Genel Şema

Bu bölümde, .vue dosyalarında çeşitli grafikler oluşturmak için FusionCharts kullanmanın genel fikrini açıklayacağız. Ama önce, ana fikri şematik olarak gösteren sözde kodu görelim.

 <template> <div> <fusioncharts :attribute_1="data_object_1" :attribute_2="data_object_2" … … ... > </fusioncharts> </div> </template> <script> export default { props: ["data_prop_received_by_the_component"], components: {}, data() { return { data_object_1: "value_1", data_object_2: "value_2", … … }; }, methods: {}, computed: {}, watch: { data_prop_received_by_the_component: { handler: function() { // some code/logic, mainly data manipulation based }, deep: true } } }; </script> <style> // component specific special CSS code here </style>

Yukarıdaki sözde kodun farklı kısımlarını anlayalım:

  • <template> içinde, üst düzey <div> içinde (bu, her bileşenin şablon HTML kodu için oldukça zorunludur), <fusioncharts> özel bileşenine sahibiz. Bu proje için vue-fusioncharts Node modülünde bulunan bileşenin tanımına sahibiz. Dahili olarak, vue-fusioncharts , yine kurulmuş olan fusioncharts modülüne dayanır. Gerekli modülleri içe aktardık ve bağımlılıklarını çözdük, src/main.js dosyasında sarmalayıcıyı global olarak (proje boyunca) kullanması talimatını verdik ve bu nedenle kullandığımız özel <fusioncharts> bileşeni için bir tanım eksikliği yok. burada. Ayrıca, özel bileşenin özel nitelikleri vardır ve özel niteliklerin her biri, kısayolunun iki nokta üst üste ( : ) sembolü olduğu v-bind yönergesi ile bir veri nesnesine (ve sırayla değerlerine) bağlıdır. Bu projede kullanılan belirli çizelgelerden bazılarını tartışırken, öznitelikler ve bunlarla ilişkili veri nesneleri hakkında daha ayrıntılı bilgi edineceğiz.
  • <script> 'de, önce bileşenin alması gereken props'ları bildirirsiniz ve ardından <fusioncharts> özniteliklerine bağlı veri nesnelerini tanımlamaya devam edersiniz. Veri nesnelerine atanan değerler, <fusioncharts> özniteliklerinin çektiği değerlerdir ve çizelgeler, alınan değerler temelinde oluşturulur. Bunların dışında kodun en ilgi çekici kısmı watch { } nesnesidir. Bu, Vue'nun planında çok özel bir nesnedir - esas olarak Vue'ya belirli verilerde meydana gelen değişiklikleri izlemesini ve ardından bu veriler için handler işlevinin nasıl tanımlandığına bağlı olarak eylemler gerçekleştirmesini söyler. Örneğin, Vue'nun alınan prop , yani sözde data_prop_received_by_the_component . prop , watch { } nesnesinde bir anahtar olur ve anahtarın değeri başka bir nesnedir - prop değiştiğinde ne yapılması gerektiğini açıklayan bir işleyici yöntemi. Değişiklikleri işlemek için böylesine zarif mekanizmalarla uygulama, tepkiselliğini koruyor. deep: true , gözlemcilerle ilişkilendirebileceğiniz bir boole bayrağını temsil eder, böylece izlenen nesne oldukça derinlemesine izlenir, yani nesnenin iç içe düzeylerinde yapılan değişiklikler bile izlenir.
    ( İzleyiciler hakkında daha fazla bilgi için resmi belgelere bakın ).

Artık genel şema hakkında bilgi sahibi olduğunuza göre, .vue bileşen dosyalarındaki çizelgelerin özel uygulamalarına geçelim. Kod oldukça açıklayıcı olacaktır ve özelliklerin yukarıda açıklanan genel şemaya nasıl uyduğunu anlamaya çalışmalısınız.

.vue Dosyalarında Grafiklerin Uygulanması

Uygulamanın çok özellikleri bir çizelgeden diğerine değişmekle birlikte, aşağıdaki açıklama hepsi için geçerlidir:

  • <template>
    Daha önce açıklandığı gibi, <fusioncharts> özel bileşeninin çeşitli öznitelikleri vardır ve bunların her biri v-bind : yönergesi kullanılarak data() işlevinde tanımlanan karşılık gelen veri nesnesine bağlıdır. Öznitelik adları, ne anlama geldiklerini oldukça açıklayıcıdır ve karşılık gelen veri nesnelerini bulmak da önemsizdir.
  • <script>
    data() işlevinde, <fusioncharts> özniteliklerinde kullanılan v-bind ( : ) yönergeleri tarafından yapılan bağlama nedeniyle, veri nesneleri ve değerleri grafiklerin çalışmasını sağlar. Bireysel veri nesnelerine derinlemesine dalmadan önce, bazı genel özelliklerden bahsetmekte fayda var:
    • Değerleri 0 veya 1 olan veri nesneleri doğaları gereği booleandır; burada 0 , mevcut olmayan/kapalı bir şeyi temsil eder ve 1 , kullanılabilirliği/açık durumu temsil eder. Bununla birlikte, diğer olası değerlerin yanı sıra, boole olmayan veri nesnelerinin de değerleri olarak 0 veya 1 olabileceği konusunda dikkatli olun - bu bağlama bağlıdır. Örneğin, varsayılan değeri 0 containerbackgroundopacity 0 lowerLimit sıfır sayısının onun değişmez değeri olduğu anlamına gelir.
    • Bazı veri nesneleri, kenar boşluğu, dolgu, yazı tipi boyutu vb. gibi CSS özellikleriyle ilgilenir. Değerin örtülü bir "px" veya piksel birimi vardır. Benzer şekilde, diğer veri nesneleri, değerleriyle ilişkili örtük birimlere sahip olabilir. Ayrıntılı bilgi için lütfen FusionCharts Dev Center'ın ilgili grafik özellikleri sayfasına bakın.
  • data() işlevinde, belki de en ilginç ve açık olmayan nesne dataSource'dur. Bu nesnenin içinde iç içe üç ana nesne vardır:
    • chart : Bu nesne, grafiğin yapılandırması ve kozmetikleriyle ilgili birçok grafik özniteliğini kapsar. Bu proje için oluşturacağınız tüm çizelgelerde bulacağınız neredeyse zorunlu bir yapıdır.
    • renk aralığı : Bu nesne, söz konusu tabloya bir şekilde özeldir ve esas olarak, tabloda kullanılan ölçeğin farklı alt aralıklarını ayırmak için birden çok renk/gölge ile ilgilenen tablolarda bulunur.
    • değer: Bu nesne, yine, ölçek aralığında vurgulanması gereken belirli bir değere sahip grafiklerde bulunur.
  • watch { } nesnesi belki de bu grafiği ve bu projede kullanılan diğer çizelgeleri hayata geçiren en önemli şeydir. Grafiklerin reaktivitesi, yani yeni bir kullanıcı sorgusundan kaynaklanan yeni değerlere göre kendilerini güncelleyen çizelgeler, bu nesnede tanımlanan izleyiciler tarafından kontrol edilir. Örneğin, bileşen tarafından alınan prop highlights için bir izleyici tanımladık ve ardından Vue'ya tüm projede izlenen nesne hakkında herhangi bir şey değiştiğinde yapması gereken eylemler hakkında talimat vermek için bir işleyici işlevi tanımladık. Bu, App.vue highlights içindeki herhangi bir nesne için yeni bir değer verdiğinde, bilgilerin bu bileşene kadar aktığı ve yeni değerin bu bileşenin veri nesnelerinde güncellendiği anlamına gelir. Değerlere bağlı olan grafik de bu mekanizma sonucunda güncellenir.

Yukarıdaki açıklamalar, büyük resmin sezgisel bir şekilde anlaşılmasını geliştirmemize yardımcı olacak oldukça geniş vuruşlardır. Kavramları sezgisel olarak anladıktan sonra, kodun kendisinden bir şey anlamadığınız zaman, her zaman Vue.js ve FusionCharts belgelerine başvurabilirsiniz. Alıştırmayı size bırakıyoruz ve bir sonraki alt bölümden itibaren bu alt bölümde ele aldığımız şeyleri açıklamayacağız.

kaynak/bileşenler/TempVarChart.vue

Saatlik Sıcaklığı gösteren bir diyagram
(Büyük önizleme)
 <template> <div class="custom-card header-card card"> <div class="card-body pt-0"> <fusioncharts type="spline" width="100%" height="100%" dataformat="json" dataEmptyMessage="i-https://i.postimg.cc/R0QCk9vV/Rolling-0-9s-99px.gif" dataEmptyMessageImageScale=39 :datasource="tempChartData" > </fusioncharts> </div> </div> </template> <script> export default { props: ["tempVar"], components: {}, data() { return { tempChartData: { chart: { caption: "Hourly Temperature", captionFontBold: "0", captionFontColor: "#000000", captionPadding: "30", baseFont: "Roboto", chartTopMargin: "30", showHoverEffect: "1", theme: "fusion", showaxislines: "1", numberSuffix: "°C", anchorBgColor: "#6297d9", paletteColors: "#6297d9", drawCrossLine: "1", plotToolText: "$label<br><hr><b>$dataValue</b>", showAxisLines: "0", showYAxisValues: "0", anchorRadius: "4", divLineAlpha: "0", labelFontSize: "13", labelAlpha: "65", labelFontBold: "0", rotateLabels: "1", slantLabels: "1", canvasPadding: "20" }, data: [], }, }; }, methods: { setChartData: function() { var data = []; for (var i = 0; i < this.tempVar.tempToday.length; i++) { var dataObject = { label: this.tempVar.tempToday[i].hour, value: this.tempVar.tempToday[i].temp }; data.push(dataObject); } this.tempChartData.data = data; }, }, mounted: function() { this.setChartData(); }, watch: { tempVar: { handler: function() { this.setChartData(); }, deep: true }, }, }; </script> <style> </style>

kaynak/bileşenler/UVindex.vue

Bu bileşen, son derece kullanışlı bir grafik içerir: Açısal Gösterge.

UV Endeksi
(Büyük önizleme)

Bileşenin kodu aşağıda verilmiştir. Angular Gauge grafik öznitelikleri hakkında ayrıntılı bilgi için Angular Gauge için FusionCharts Dev Center sayfasına bakın.

 <template> <div class="highlights-item col-md-4 col-sm-6 col-xs-12 border-top"> <div> <fusioncharts :type="type" :width="width" :height="height" :containerbackgroundopacity="containerbackgroundopacity" :dataformat="dataformat" :datasource="datasource" ></fusioncharts> </div> </div> </template> <script> export default { props: ["highlights"], components: {}, data() { return { type: "angulargauge", width: "100%", height: "100%", containerbackgroundopacity: 0, dataformat: "json", datasource: { chart: { caption: "UV Index", captionFontBold: "0", captionFontColor: "#000000", captionPadding: "30", lowerLimit: "0", upperLimit: "15", lowerLimitDisplay: "1", upperLimitDisplay: "1", showValue: "0", theme: "fusion", baseFont: "Roboto", bgAlpha: "0", canvasbgAlpha: "0", gaugeInnerRadius: "75", gaugeOuterRadius: "110", pivotRadius: "0", pivotFillAlpha: "0", valueFontSize: "20", valueFontColor: "#000000", valueFontBold: "1", tickValueDistance: "3", autoAlignTickValues: "1", majorTMAlpha: "20", chartTopMargin: "30", chartBottomMargin: "40" }, colorrange: { color: [ { minvalue: "0", maxvalue: this.highlights.uvIndex.toString(), code: "#7DA9E0" }, { minvalue: this.highlights.uvIndex.toString(), maxvalue: "15", code: "#D8EDFF" } ] }, annotations: { groups: [ { items: [ { id: "val-label", type: "text", text: this.highlights.uvIndex.toString(), fontSize: "20", font: "Source Sans Pro", fontBold: "1", fillcolor: "#212529", x: "$gaugeCenterX", y: "$gaugeCenterY" } ] } ] }, dials: { dial: [ { value: this.highlights.uvIndex.toString(), baseWidth: "0", radius: "0", borderThickness: "0", baseRadius: "0" } ] } } }; }, methods: {}, computed: {}, watch: { highlights: { handler: function() { this.datasource.colorrange.color[0].maxvalue = this.highlights.uvIndex.toString(); this.datasource.colorrange.color[1].minvalue = this.highlights.uvIndex.toString(); this.datasource.annotations.groups[0].items[0].text = this.highlights.uvIndex.toString(); }, deep: true } } }; </script>

kaynak/bileşenler/Visibility.vue

Bu bileşende, aşağıdaki resimde gösterildiği gibi görünürlüğü temsil etmek için bir Yatay Doğrusal Gösterge kullanıyoruz:

Hava Görünürlüğünü (16km) temsil eden Yatay Doğrusal Göstergenin ekran görüntüsü
(Büyük önizleme)

Bileşenin kodu aşağıda verilmiştir. Bu çizelge türünün farklı niteliklerinin derinlemesine anlaşılması için lütfen Yatay Doğrusal Gösterge için FusionCharts Geliştirme Merkezi sayfasına bakın.

 <template> <div class="highlights-item col-md-4 col-sm-6 col-xs-12 border-left border-right border-top"> <div> <fusioncharts :type="type" :width="width" :height="height" :containerbackgroundopacity="containerbackgroundopacity" :dataformat="dataformat" :datasource="datasource" > </fusioncharts> </div> </div> </template> <script> export default { props: ["highlights"], components: {}, methods: {}, computed: {}, data() { return { type: "hlineargauge", width: "100%", height: "100%", containerbackgroundopacity: 0, dataformat: "json", creditLabel: false, datasource: { chart: { caption: "Air Visibility", captionFontBold: "0", captionFontColor: "#000000", baseFont: "Roboto", numberSuffix: " km", lowerLimit: "0", upperLimit: "40", showPointerShadow: "1", animation: "1", transposeAnimation: "1", theme: "fusion", bgAlpha: "0", canvasBgAlpha: "0", valueFontSize: "20", valueFontColor: "#000000", valueFontBold: "1", pointerBorderAlpha: "0", chartBottomMargin: "40", captionPadding: "30", chartTopMargin: "30" }, colorRange: { color: [ { minValue: "0", maxValue: "4", label: "Fog", code: "#6297d9" }, { minValue: "4", maxValue: "10", label: "Haze", code: "#7DA9E0" }, { minValue: "10", maxValue: "40", label: "Clear", code: "#D8EDFF" } ] }, pointers: { pointer: [ { value: this.highlights.visibility.toString() } ] } } }; }, watch: { highlights: { handler: function() { this.datasource.pointers.pointer[0].value = this.highlights.visibility.toString(); }, deep: true } } }; </script>

kaynak/bileşenler/WindStatus.vue

Bu bileşen rüzgar hızını ve yönünü gösterir (fizik bilginiz varsa rüzgar hızı) ve bir vektörü grafik kullanarak temsil etmek çok zordur. Bu gibi durumlarda, bazı güzel resimler ve metin değerleri yardımıyla bunları temsil etmenizi öneririz. Düşündüğümüz temsil tamamen CSS'ye bağlı olduğundan, onu CSS ile ilgilenen bir sonraki bölümde uygulayacağız. Ancak, yaratmayı hedeflediğimiz şeye bir göz atın:

Rüzgar Durumu: Rüzgar Yönü (sol) ve Rüzgar Hızı (sağ)
(Büyük önizleme)
 <template> <div class="highlights-item col-md-4 col-sm-6 col-xs-12 border-top"> <div> <div class="card-heading pt-5">Wind Status</div> <div class="row pt-4 mt-4"> <div class="col-sm-6 col-md-6 mt-2 text-center align-middle"> <p class="card-sub-heading mt-3">Wind Direction</p> <p class="mt-4"><img src="../assets/winddirection.svg" height="40" width="40"></p> <p class="card-value mt-4">{{ highlights.windStatus.derivedWindDirection }}</p> </div> <div class="col-sm-6 col-md-6 mt-2"> <p class="card-sub-heading mt-3">Wind Speed</p> <p class="mt-4"><img src="../assets/windspeed.svg" height="40" width="40"></p> <p class="card-value mt-4">{{ highlights.windStatus.windSpeed }} km/h</p> </div> </div> </div> </div> </template> <script> export default { props: ["highlights"], components: {}, data() { return {}; }, methods: {}, computed: {} }; </script>

Highlights.vue ile Özetleme

Content.vue ve Highlights.vue hariç tüm bileşenler için CSS ile kod uyguladığımızı hatırlayın. Content.vue yalnızca verileri aktaran aptal bir bileşen olduğundan, ihtiyaç duyduğu minimal stil zaten ele alınmıştır. Ayrıca, kenar çubuğunu ve çizelgeleri içeren kartları biçimlendirmek için uygun kodu zaten yazdık. Bu nedenle, tek yapmamız gereken, Highlights.vue , öncelikle CSS sınıflarını kullanmayı içeren bazı stilistik bitler eklemek:

 <template> <div class="custom-content-card content-card card"> <div class="card-body pb-0"> <div class="content-header h4 text-center pt-2 pb-3">Highlights</div> <div class="row"> <uv-index :highlights="highlights"></uv-index> <visibility :highlights="highlights"></visibility> <wind-status :highlights="highlights"></wind-status> </div> </div> </div> </template> <script> import UVIndex from "./UVIndex.vue"; import Visibility from "./Visibility.vue"; import WindStatus from "./WindStatus.vue"; export default { props: ["highlights"], components: { "uv-index": UVIndex, "visibility": Visibility, "wind-status": WindStatus, }, }; </script>

Dağıtım ve Kaynak Kodu

Sıralı grafikler ve stiller ile işimiz bitti! Yaratılışınızın güzelliğini takdir etmek için bir dakikanızı ayırın.

Sonuç
(Büyük önizleme)

Artık uygulamanızı dağıtmanın ve meslektaşlarınızla paylaşmanın zamanı geldi. Dağıtım hakkında fazla bir fikriniz yoksa ve size yardım etmemizi bekliyorsanız, dağıtım fikirlerimizi ele almak için buraya bakın. Bağlantılı makale ayrıca her grafiğin sol alt kısmındaki FusionCharts filigranının nasıl kaldırılacağına ilişkin öneriler içerir.

Bir yeri karıştırırsanız ve bir referans noktası istiyorsanız, kaynak kodu Github'da mevcuttur.