Vue js 3 & composition api weather app

فهاد ال projet غادي نشوفوا كيفاش نقادو weather app ب vue js 3 و composition api لي هو تطبيق كيعرض حالة الطقس وغادي نخدموا ب algolia places باش نسترجعوا المدن و dark sky api باش نسترجعوا حالة الطقس.

نظرة سريعة بالفيديو


1- إضافة Home component


أول حاجة باش تزيد projet جديد ب vuejs cli شوف الفيديو المرفق من بعد زيد dossier سميه components فيه زيد vuejs component سميه Home فيه كنسترجع ل components لي غادي نزيدهم من بعد ولي الدور ديالهم هو عرض حالة الطقس الحالية وديال الأيام القادمة ولي غادي يمكنا من البحث بواسطة مدينة.

كنسترجع حالة الطقس ديال اليوم والأيام القادمة من dark sky api وكنعطيها ل component لي غادي نزيدو من بعد كيف قلنا.

الكود ديال الملف هو : 

                                    
                                        <template>
  <div class="container">
    <Search @search-result="getWeather" />
    <CurrentWeather :weather="state.weather" />
    <ComingDays :data="state.data" />
  </div>
</template>

<script>
import Search from "./Search.vue";
import CurrentWeather from "./CurrentWeather.vue";
import ComingDays from "./ComingDays.vue";
import { reactive } from "vue";

export default {
  name: "Home",
  components: { Search, CurrentWeather, ComingDays },
  setup() {
    const state = reactive({
      weather: null,
      data: null,
      key: "1d5cfbb4b1ba74f6287033207b5f59d7",
    });

    async function getWeather(city) {
      const proxy = "https://cors-anywhere.herokuapp.com/";
      const apiURL = `https://api.darksky.net/forecast/${state.key}/${city.latlng.lat},${city.latlng.lng}?lang=fr&units=ca`;
      const data = await fetch(proxy + apiURL);
      const resData = await data.json();
      const weatherData = {
        time: resData.currently.time,
        summary: resData.currently.summary,
        icon: `${resData.currently.icon}.png`,
        temperature: `${Math.round(resData.currently.temperature)}˚C`,
        humidity: resData.currently.humidity,
      };
      state.weather = weatherData;
      state.data = resData.daily.data;
    }

    return {
      getWeather,
      state,
    };
  },
};
</script>

<style>
body {
  background: #ccc;
  font-family: "Franklin Gothic Medium", "Arial Narrow", Arial, sans-serif;
}
</style>
                                    
                                

2- إضافة CurrentWeather component


من بعد زيد component سميه CurrentWeather فيه كنستقبل ل weather object لي جاني من Home بإستعمال vuejs props لي هي بحال vuejs watch كتراقب القيمة أول مكتغير كتعطينا القيمة الجديدة. 

منبعد كنعرض المعلومات لي وصلوني ولي هما حالة الطقس الحالية.

الكود ديال الملف هو :

                                    
                                        <template>
  <div className="weather border-bottom" v-if="weather">
    <div className="weather-header">
      <img
        :src="state.iconLink + weather.icon"
        alt="icon"
        width="80"
        height="80"
        className="img-fluid"
      />
      <h3 className="temperature font-weight-bold">
        {{ weather.temperature }}
      </h3>
    </div>
    <h3 className="temperature my-2 font-weight-bold">
      {{ state.currentDate }}
    </h3>
    <h5 className="font-weight-bold">{{ weather.summary }}</h5>
  </div>
</template>

<script>
import { reactive } from "vue";
import moment from "moment";
import "moment/locale/fr";

export default {
  props: {
    weather: Object,
  },
  setup() {
    const state = reactive({
      iconLink: "https://darksky.net/images/weather-icons/",
      currentDate: moment().calendar(),
    });

    return {
      state,
    };
  },
};
</script>

<style scoped>
.weather {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
}
.weather-header {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  width: 100%;
}
</style>
                                    
                                

3- إضافة ComingDays component


من بعد زيد component سميه ComingDays فيه كنستقبل data object لي جاني من Home بإستعمال vuejs props 

منبعد كنعرض المعلومات لي وصلوني ولي هما حالة الطقس ديال الأيام القادمة.

الكود ديال الملف هو :

                                      
                                        <template>
  <div className="row mt-3 mx-auto" v-if="data">
    <div className="col-md-2 mb-1" v-for="day in data" :key="day.time">
      <div className="day shadow rounded">
        <span className="text-dark">
          {{ convertTimestamp(day.time) }}
        </span>
        <img
          :src="state.iconLink + day.icon + '.png'"
          alt="icon"
          width="50"
          height="50"
          className="img-fluid"
        />
        <span className="text-dark">
          Max: {{ Math.round(day.temperatureHigh) + "˚C" }}
        </span>
        <span className="text-dark">
          Min: {{ Math.round(day.temperatureLow) + "˚C" }}
        </span>
      </div>
    </div>
  </div>
</template>

<script>
import { reactive } from "vue";
import moment from "moment";
import "moment/locale/fr";

export default {
  props: {
    data: Object,
  },
  setup() {
    const state = reactive({
      iconLink: "https://darksky.net/images/weather-icons/",
    });

    function convertTimestamp(time) {
      let day = moment
        .unix(time)
        .locale("fr")
        .utc();
      return day.format("dddd MMM Do");
    }

    return {
      state,
      convertTimestamp,
    };
  },
};
</script>

<style scoped>
.day {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 10px;
  background-color: beige;
  height: 150px;
  width: 150px;
}
</style>
                                      
                                    

4- إضافة Search component


من بعد زيد component سميه Search فيه عندي ل form ديال البحث بواسطة مدينة ولي كنخدم ب algolia places باش نعرض المدن المتاحة ونختار منها منبعد مكنختار كنخدم ب vuejs emit باش كنرسل المدينة لي اختاريت ل Home component ولي فيه كنسترجع حالة الطقس الخاصة بها.

الكود ديال الملف هو :

                                        
                                            <template>
  <div className="row mt-4">
    <div className="col-md-6 mx-auto">
      <div className="form-group">
        <input
          type="search"
          name="city"
          id="address-input"
          autoComplete="off"
          className="form-control"
          placeholder="Entrer une ville"
          aria-describedby="helpId"
        />
      </div>
    </div>
  </div>
</template>

<script>
import { onMounted, reactive } from "vue";
import places from "places.js";

export default {
  emits: ["search-result"],
  setup(props, { emit }) {
    const state = reactive({
      appId: "pl84BDTK7HU7",
      apiKey: "671cd803cf905b98ff3217c773e5207a",
    });

    function getPlaces() {
      let placesAutocomplete = places({
        appId: state.appId,
        apiKey: state.apiKey,
        container: document.querySelector("#address-input"),
      });
      placesAutocomplete.on("change", function($event) {
        emit("search-result", $event.suggestion);
      });
    }

    onMounted(() => {
      getPlaces();
    });

    return {};
  },
};
</script>

<style scoped></style>
                                        
                                    

5- تعديل App component


فل component App كندير تعديلات وكنسترجع ل Home component ونعرضوا.

ممكن ت télécharger le projet من github.

الكود ديال App.vue بعد التعديل هو :

                                        
                                            <template>
  <Home />
</template>

<script>
import Home from "./components/Home.vue";

export default {
  name: "App",
  components: {
    Home,
  },
};
</script>

<style></style>
                                        
                                    

كلمات مفاتيح :