GithubHelp home page GithubHelp logo

learn-simple-vite-vue3-tailwind's Introduction

Vue Simple Apps with Tailwindcss

Demo

https://simple-vue-tailwind.web.app/

Short Documentation

Disclaimer:

  • This documentation is using pnpm
  • This code is using Vue v3 with Composition API (not Options API)

Initialize Apps

  1. pnpm create vite
  2. name your project
  3. select Framework: vue,
  4. select a variant: vue
  5. cd path/to/project/folder
  6. pnpm install
  7. delete src/assets/, src/components/HelloWorld.vue
  8. pnpm install -D tailwindcss postcss autoprefixer
  9. pnpm exec tailwindcss init -p
  10. edit tailwind.config.js
    module.exports = {
      content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx,svelte,md,mdx}"],
      theme: {
        extend: {},
      },
      plugins: [],
    };
  11. create file src/index.css
  12. edit index.css
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    
    .custom-container {
      @apply container p-4 min-w-full min-h-screen flex flex-col items-center justify-center text-center;
    }
    
    .custom-subcontainer {
      @apply flex flex-row justify-center items-center;
    }
    
    .h1 {
      @apply text-4xl font-medium mb-4;
    }
    
    .h2 {
      @apply text-2xl font-medium mb-4;
    }
    
    .btn {
      @apply px-4 py-2 my-2 bg-sky-300 hover:bg-sky-600 text-slate-700 hover:text-slate-300 font-bold rounded-3xl w-48;
    }
    
    .form-input {
      @apply px-4 py-2 my-2 bg-white border border-gray-300 rounded-3xl w-full;
    }
    
    table {
      @apply table-auto border border-collapse border-slate-500;
    }
    
    td,
    th {
      @apply border border-slate-500 p-2;
    }
  13. edit main.js
    import { createApp } from "vue";
    import App from "./App.vue";
    // import the tailwind css here
    import "./index.css";
    
    createApp(App).mount("#app");
  14. edit App.vue
    <script setup>
    // This starter template is using Vue 3 <script setup> SFCs
    // Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
    </script>
    
    <template>
      <div class="custom-container bg-slate-200">
        <p class="h1">Simple Vue Apps with Tailwind</p>
      </div>
    </template>
    
    <style></style>
  15. run the app pnpm run dev

FirstComponent

  1. create file src/components/FirstComponent.vue
  2. edit FirstComponent.vue
    <script setup>
    import { ref } from "vue";
    
    // ref is for reactive value
    const count = ref(0);
    
    // method for set count state
    function addCount() {
      count.value++;
    }
    
    // method for reset count state
    function resetCount() {
      count.value = 0;
    }
    </script>
    
    <template>
      <div>
        <h2 class="h2">First Component</h2>
        <h3>
          <!-- conditional rendering -->
          <span v-if="count === 0">Don't you dare to click me !</span>
          <span v-else-if="count >= 1">
            How dare you click me {{ count }} time{{ count > 1 ? "s" : "" }}
          </span>
        </h3>
        <p>
          <!-- bind event on click with addCount -->
          <button class="btn" v-on:click="addCount">Dare-to-click</button>
        </p>
        <p>
          <!-- bind event on click with resetCount -->
          <!-- @ is shorthand for v-on: -->
          <button class="btn" @click="resetCount">Forget-me-not</button>
        </p>
      </div>
    </template>
    
    <style></style>
  3. edit App.vue
    <script setup>
    // This starter template is using Vue 3 <script setup> SFCs
    // Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
    
    // import the component here
    import FirstComponent from "./components/FirstComponent.vue";
    </script>
    
    <template>
      <div class="custom-container bg-slate-200">
        <p class="h1">Simple Vue Apps with Tailwind</p>
        <!-- Call the FirstComponent -->
        <FirstComponent />
      </div>
    </template>
    
    <style></style>

SecondComponent

  1. create file src/components/SecondComponent.vue
  2. create file src/components/SecondComponentSubContent.vue
  3. edit SecondComponentSubContent.vue
    <script setup>
    // get a props from parent component named 'textInput'
    // via defineProps
    defineProps(["textInput"]);
    </script>
    
    <template>
      <div>
        <pre v-if="textInput === ''">I have nothing to show</pre>
        <pre v-else>I write: {{ textInput }}</pre>
      </div>
    </template>
    
    <style></style>
  4. edit SecondComponent.vue
    <script setup>
    import { ref } from "vue";
    
    // We will create a child component to hold the content
    import SecondComponentSubContent from "./SecondComponentSubContent.vue";
    
    // state for the text
    const textInput = ref("");
    </script>
    
    <template>
      <div>
        <h2 class="h2">Second Component</h2>
        <div class="custom-subcontainer">
          <!-- Form Section -->
          <section class="mr-4">
            <form>
              <!-- Two way data binding automatically using v-model -->
              <input
                class="form-input"
                type="text"
                placeholder="Write me pl0x"
                v-model="textInput"
              />
            </form>
          </section>
          <section>
            <!-- Content section  -->
    
            <!-- pass textInput to SecondComponentSubContent -->
            <SecondComponentSubContent v-bind:textInput="textInput" />
          </section>
        </div>
      </div>
    </template>
    
    <style></style>
  5. edit App.vue
    <script setup>
    // This starter template is using Vue 3 <script setup> SFCs
    // Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
    
    // import the component here
    import FirstComponent from "./components/FirstComponent.vue";
    // import the second component here
    import SecondComponent from "./components/SecondComponent.vue";
    </script>
    
    <template>
      <div class="custom-container bg-slate-200">
        <p class="h1">Simple Vue Apps with Tailwind</p>
        <!-- Create new section to hold FirstComponent -->
        <FirstComponent />
        <!-- Create new section to hold FirstComponent -->
        <SecondComponent />
      </div>
    </template>
    
    <style></style>

ThirdComponent

  1. create file src/components/ThirdComponent.vue
  2. create file src/components/ThirdComponentSubTable.vue
  3. create file src/components/ThirdComponentSubTableContent.vue
  4. edit file ThirdComponentSubTableContent.vue
    <script setup>
    defineProps(["item"]);
    </script>
    
    <template>
      <tr v-bind:key="item.id">
        <td>{{ item.first_name }}</td>
        <td>{{ item.last_name }}</td>
        <td>{{ item.email }}</td>
        <td>
          <img v-bind:src="item.avatar" />
        </td>
      </tr>
    </template>
    
    <style></style>
  5. edit file ThirdComponentSubTable.vue
    <script setup>
    import ThirdComponentSubTableContent from "./ThirdComponentSubTableContent.vue";
    
    defineProps(["extData"]);
    </script>
    
    <template>
      <table class="table-auto">
        <thead>
          <tr>
            <th>first_name</th>
            <th>last_name</th>
            <th>email</th>
            <th>avatar</th>
          </tr>
        </thead>
        <tbody>
          <!-- Create the loop for rendering the data  -->
          <!-- Loop the table rows and pass the item -->
          <ThirdComponentSubTableContent
            v-for="item in extData"
            v-bind:key="item.id"
            v-bind:item="item"
          />
        </tbody>
      </table>
    </template>
    
    <style></style>
  6. edit file ThirdComponent.vue
    <script setup>
    import { onMounted, onUnmounted, ref } from "vue";
    import ThirdComponentSubTable from "./ThirdComponentSubTable.vue";
    
    const extData = ref([]);
    
    const fetchData = async () => {
      // fetch data from external API
      const response = await fetch("https://reqres.in/api/users");
      const jsonData = await response.json();
    
      // set fetched data to state
      extData.value = jsonData.data.slice(0, 3);
    };
    
    // we will fetch the data from the external API
    // using the methods that we have created
    // the fetchExternalData method
    
    // this is the same as componentDidMount on React
    onMounted(() => {
      fetchData();
    });
    
    // this is the same as componentDidUnmount on React
    onUnmounted(() => {});
    </script>
    
    <template>
      <div>
        <h2 class="h2">Third Component</h2>
        <ThirdComponentSubTable v-bind:extData="extData"></ThirdComponentSubTable>
      </div>
    </template>
    
    <style></style>
  7. edit file App.vue
    <script setup>
    // This starter template is using Vue 3 <script setup> SFCs
    // Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
    
    // import the component here
    import FirstComponent from "./components/FirstComponent.vue";
    // import the second component here
    import SecondComponent from "./components/SecondComponent.vue";
    // import the third component here
    import ThirdComponent from "./components/ThirdComponent.vue";
    </script>
    
    <template>
      <div class="custom-container bg-slate-200">
        <p class="h1">Simple Vue Apps with Tailwind</p>
        <!-- Create new section to hold FirstComponent -->
        <section>
          <FirstComponent />
        </section>
        <!-- Create new section to hold SecondComponent -->
        <section>
          <SecondComponent />
        </section>
        <!-- Create new section to hold ThirdComponent -->
        <section>
          <ThirdComponent />
        </section>
      </div>
    </template>
    
    <style></style>

Pre-FourthComponent (Router)

  1. pnpm add vue-router@4
  2. edit index.css
    .link {
      @apply underline text-sky-600 hover:text-green-600 m-2;
    }
  3. create folder src/routes
  4. create file src/routes/route.js
  5. edit main.js
    import { createApp } from "vue";
    import App from "./App.vue";
    // import the router that we have created here
    import router from "./routes/route";
    // import the tailwind css here
    import "./index.css";
    
    const app = createApp(App);
    app.use(router);
    app.mount("#app");
  6. edit route.js
    // import createRouter for using the vue-router
    // import createWebHistory to use the history mode
    import { createRouter, createWebHistory } from "vue-router";
    import ThirdComponent from "../components/ThirdComponent.vue";
    
    // declare the routes needed for the application
    const routes = [{ path: "/third-component", component: ThirdComponent }];
    
    // declare the router to be used by Vue
    const router = createRouter({
      history: createWebHistory(),
      routes,
    });
    
    export default router;
  7. edit App.vue
    <script setup>
    // This starter template is using Vue 3 <script setup> SFCs
    // Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
    
    // import the component here
    import FirstComponent from "./components/FirstComponent.vue";
    // import the second component here
    import SecondComponent from "./components/SecondComponent.vue";
    // import the third component here
    import ThirdComponent from "./components/ThirdComponent.vue";
    </script>
    
    <template>
      <div class="custom-container bg-slate-200">
        <p class="h1">Simple Vue Apps with Tailwind</p>
        <!-- Create new section to hold FirstComponent -->
        <section>
          <FirstComponent />
        </section>
        <!-- Create new section to hold SecondComponent -->
        <section>
          <SecondComponent />
        </section>
        <!-- Create new section to hold ThirdComponent -->
        <section>
          <!-- <ThirdComponent /> -->
          <nav>
            <!--  Declare the link in here (href)  -->
            <router-link class="link" to="/">Back</router-link>
            <router-link class="link" to="/third-component"
              >Third Component</router-link
            >
          </nav>
          <!-- create the router-view to hold the component -->
          <router-view></router-view>
        </section>
      </div>
    </template>
    
    <style></style>

FourthComponent

  1. create file src/components/FourthComponent.vue
  2. create file src/components/FourthComponentSubTable.vue
  3. create file src/components/FourthComponentSubTableContent.vue
  4. create file src/components/FourthComponentSubInput.vue
  5. edit src/routes/route.js to import FourthComponent.vue and adding routes to fourth-component
    // import createRouter for using the vue-router
    // import createWebHistory to use the history mode
    import { createRouter, createWebHistory } from "vue-router";
    import ThirdComponent from "../components/ThirdComponent.vue";
    // import fourth component
    import FourthComponent from "../components/FourthComponent.vue";
    
    // declare the routes needed for the application
    const routes = [
      { path: "/third-component", component: ThirdComponent },
      // declare FourthComponent
      {
        path: "/fourth-component",
        component: FourthComponent,
      },
    ];
    
    // declare the router to be used by Vue
    const router = createRouter({
      history: createWebHistory(),
      routes,
    });
    
    export default router;
  6. edit App.vue to add FourthComponent
    <script setup>
    // This starter template is using Vue 3 <script setup> SFCs
    // Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
    
    // import the component here
    import FirstComponent from "./components/FirstComponent.vue";
    // import the second component here
    import SecondComponent from "./components/SecondComponent.vue";
    // import the third component here
    import ThirdComponent from "./components/ThirdComponent.vue";
    </script>
    
    <template>
      <div class="custom-container bg-slate-200">
        <p class="h1">Simple Vue Apps with Tailwind</p>
        <!-- Create new section to hold FirstComponent -->
        <section>
          <FirstComponent />
        </section>
        <!-- Create new section to hold SecondComponent -->
        <section>
          <SecondComponent />
        </section>
        <!-- Create new section to hold ThirdComponent -->
        <section>
          <!-- <ThirdComponent /> -->
          <nav>
            <!--  Declare the link in here (href)  -->
            <router-link class="link" to="/">Back</router-link>
            <router-link class="link" to="/third-component"
              >Third Component</router-link
            >
            <router-link class="link" to="/fourth-component"
              >Fourth Component</router-link
            >
          </nav>
          <!-- create the router-view to hold the component -->
          <router-view></router-view>
        </section>
      </div>
    </template>
    
    <style></style>
  7. edit FourthComponent.vue
    <script setup>
    import { onMounted, onUnmounted, ref } from "vue";
    import FourthComponentSubTable from "./FourthComponentSubTable.vue";
    import FourthComponentSubInput from "./FourthComponentSubInput.vue";
    
    // state for fetched external data
    // initial value is an empty array
    const extData = ref([]);
    
    // state for selected row (we only fetch the email, so initial state will be string)
    const selectedExtData = ref("");
    
    // declare function to set the ext data
    const setExtData = (data) => {
      extData.value = data;
    };
    
    // declare function to set the selected email
    const setSelectedEmail = (email) => {
      selectedExtData.value = email;
    };
    
    const fetchData = async () => {
      // fetch data from external API
      const response = await fetch("https://reqres.in/api/users");
      const jsonData = await response.json();
    
      // set fetched data to state
      setExtData(jsonData.data.slice(3, 6));
    };
    
    // we will fetch the data when this FourthComponent is rendered
    // using the onMounted hook to fetch the data
    // this is the same as componentDidMount on React
    onMounted(() => {
      fetchData();
    });
    
    // this is the same as componentDidUnmount on React
    onUnmounted(() => {});
    </script>
    
    <template>
      <div>
        <h2 className="h2">Fourth Component</h2>
        <FourthComponentSubInput
          v-bind:selectedExtData="selectedExtData"
        ></FourthComponentSubInput>
        <!-- pass the setSelectedEmail function here -->
        <FourthComponentSubTable
          v-bind:extData="extData"
          v-on:setSelectedEmail="setSelectedEmail"
        ></FourthComponentSubTable>
      </div>
    </template>
  8. edit FourthComponentSubInput.vue
    <script setup>
    defineProps(["selectedExtData"]);
    </script>
    
    <template>
      <div>
        <input
          type="text"
          className="form-input"
          placeholder="Choose from below"
          v-bind:value="selectedExtData"
          disabled
        />
      </div>
    </template>
  9. edit FourthComponentSubTable.vue
    <script setup>
    import FourthComponentSubTableContent from "./FourthComponentSubTableContent.vue";
    
    // Receive the passed props extData to this component
    defineProps(["extData"]);
    
    // Receive the passed events setSelectedEmail to this component
    const emit = defineEmits(["setSelectedEmail"]);
    
    // define the function to use the emitted event from parent
    const setSelectedEmail = (email) => {
      emit("setSelectedEmail", email);
    };
    </script>
    
    <template>
      <table className="table-auto">
        <thead>
          <tr>
            <th>first_name</th>
            <th>last_name</th>
            <th>email</th>
            <th>avatar</th>
            <th>action</th>
          </tr>
        </thead>
        <tbody>
          <!-- Create the loop for rendering the data  -->
    
          <!-- Loop the table rows and pass the item function from props -->
          <FourthComponentSubTableContent
            v-for="item in extData"
            v-bind:key="item.id"
            v-bind:item="item"
            v-on:setSelectedEmail="setSelectedEmail"
          />
        </tbody>
      </table>
    </template>
  10. edit FourthComponentSubTableContent.vue
    <script setup>
    defineProps(["item"]);
    
    // Receive the passed events setSelectedEmail to this component
    const emit = defineEmits(["setSelectedEmail"]);
    
    // define the function to use the emitted event from parent
    const setSelectedEmail = (email) => {
      emit("setSelectedEmail", email);
    };
    </script>
    
    <template>
      <tr>
        <td>{{ item.first_name }}</td>
        <td>{{ item.last_name }}</td>
        <td>{{ item.email }}</td>
        <td>
          <img v-bind:src="item.avatar" />
        </td>
        <td>
          <button className="btn" v-on:click="setSelectedEmail(item.email)">
            Choose Me pl0x
          </button>
        </td>
      </tr>
    </template>

learn-simple-vite-vue3-tailwind's People

Contributors

withered-flowers avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.