Font Awesome是一个流行的CSS库,用于向Web应用程序添加图标。它可以作为原始CSS包提供,也有主要前端框架的版本。对于Vue.js,我们可以使用vue-fontawesome在我们的应用程序中添加图标。
在本文中,我们将制作一个购物清单应用程序,用户可以在其中使用MealDB API搜索想要烹饪的菜肴,并从中添加所需的食材。我们将在按钮上添加涟漪效果,并在鼠标指针移到按钮上并列出项目时使其突出显示。
要开始构建应用程序,我们可以通过运行来运行Vue CLI npx @vue/cli grocery-app
。在向导中,选择“手动选择功能”,然后选择Babel,Vuex,Vue Router和CSS Preprocessor。
接下来,我们安装一些其他软件包。我们需要Axios来发出HTTP请求,需要BootstrapVue来样式化,需要Vue Font Awesome来添加图标,需要Vee-Validate来进行表单验证,并需要Vue Ripple指令来增加波纹效果。要安装它们,我们运行:
npm i axios @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/vue-fontawesome axios bootstrap-vue vee-validate vue-ripple-directive
安装所有软件包后,我们可以构建应用程序。我们首先添加用于添加食品的表格。GroceryForm.vue
在components文件夹中创建一个文件并添加:
<template>
<div>
<ValidationObserver ref="observer" v-slot="{ invalid }">
<b-form @submit.prevent="onSubmit" novalidate>
<b-form-group label="Search for Dish and Add Ingredients From Result">
<ValidationProvider name="keyword" rules="required" v-slot="{ errors }">
<b-form-input
type="text"
:state="errors.length == 0"
v-model="form.keyword"
required
placeholder="Search for Dish and Add Ingredients From Result"
name="keyword"
></b-form-input>
<b-form-invalid-feedback :state="errors.length == 0">{{errors.join('. ')}}</b-form-invalid-feedback>
</ValidationProvider>
</b-form-group>
<b-button v-ripple.mouseover.500 type="submit" variant="primary">Find Dishes</b-button>
</b-form>
</ValidationObserver>
<b-card v-for="(m, i) in meals" :title="m.strMeal" :key="i">
<b-card-text>
<b-list-group>
<b-list-group-item
v-for="(key, index) in Object.keys(m).filter(k => k.includes('strIngredient') && m[k])"
:key="index"
v-ripple.mouseover="'rgba(255, 255, 255, 0.35)'"
>{{m[key]}}</b-list-group-item>
</b-list-group>
</b-card-text>
<b-button
v-ripple.mouseover.500
variant="primary"
@click="addToGroceryList(i)"
>Add Ingredients to Grocery List</b-button>
</b-card>
<h4>Your Chosen Ingredients</h4>
<b-list-group>
<b-list-group-item v-for="(ingredient, i) of ingredients" :key="i" v-ripple.mouseover>
{{ingredient}}
<font-awesome-icon icon="times" class="float-right" @click="removeIngredient(i)" />
</b-list-group-item>
</b-list-group>
<br />
<b-button v-ripple.mouseover.500 type="button" variant="primary" @click="saveGroceryList()">Save</b-button>
<b-button v-ripple.mouseover.500 type="reset" variant="danger" @click="cancel()">Cancel</b-button>
</div>
</template>
<script>
import { requestsMixin } from "@/mixins/requestsMixin";
import { faTimes } from "@fortawesome/free-solid-svg-icons";
export default {
name: "GroceryForm",
mixins: [requestsMixin],
components: {
faTimes
},
data() {
return {
form: {},
meals: [],
ingredients: []
};
},
computed: {
grocery() {
return this.$store.state.grocery;
}
},
methods: {
cancel() {
this.$emit("cancelled");
},
async onSubmit() {
const isValid = await this.$refs.observer.validate();
if (!isValid) {
return;
}
const { data } = await this.findDishes(this.form.keyword);
this.meals = data.meals;
},
addToGroceryList(index) {
const meal = this.meals[index];
const keys = Object.keys(meal).filter(
k => k.includes("strIngredient") && meal[k]
);
const ingredients = keys.map(k => meal[k]);
this.ingredients = Array.from(
new Set(this.ingredients.concat(ingredients))
);
},
removeIngredient(index) {
this.ingredients.splice(index, 1);
},
async saveGroceryList() {
const payload = { ingredients: this.ingredients };
if (!this.groceryListId) {
await this.addGrocery(payload);
} else {
await this.editGrocery(payload);
}
const { data } = await this.getGrocery();
this.$store.commit("setGrocery", data);
this.$emit("saved");
}
},
watch: {
grocery: {
handler(val) {
this.ingredients = val.ingredients || [];
},
deep: true,
immediate: true
}
}
};
</script>
<style lang="scss" scoped>
.delete {
cursor: pointer;
}
</style>
该表单使用户可以使用给定的关键字搜索菜肴,然后返回菜肴的配料列表,然后用户可以将其添加到已删除重复项的列表中。我们使用Vee-Validate来验证我们的输入。我们使用ValidationObserver
组件来监视组件内部表单的有效性,并ValidationProvider
检查组件内部输入的输入值的验证规则。在中ValidationProvider
,我们有用于文本输入字段的BootstrapVue输入。在b-form-input
组件中。我们还添加了Vee-Validate验证,以确保用户在提交之前填写了日期。我们keyword
在rules
道具中设置了必填字段,以便用户在搜索之前必须输入内容。
我们在表单底部的列表中有包含成分列表的按钮,用于删除每个成分。这就是为什么我们在faTimes
此处导入图标的原因,该图标显示为“ x”,以便用户可以单击并删除它。如果单击该元素,removeIngredient
则调用该函数。然后,用户单击表单底部的“保存”,然后saveGroceryList
调用该函数,将列表保存到我们的后端。
在此组件中,我们还有一个watch
块来监视grocery
值,该块是从必须构建的Vuex存储中获得的。随着grocery
值的更新,我们将获得最新的配料清单。
我们使用Vue Ripple将波纹效果应用到按钮和列表行。v-ripple.mouseover.500
表示使用此指令将鼠标悬停在元素上时,纹波效果将显示500毫秒。要为波纹效果应用不同于默认颜色的颜色,我们还可以在伪指令的参数中指定颜色值,就像in中一样v-ripple.mouseover=”’rgba(255, 255, 255, 0.35)’”
。波纹将具有指定的颜色。
我们使用样式设置元素以删除表单,cursor:pointer
因此鼠标图标将显示一只手而不是箭头。
接下来,我们创建一个mixins
文件夹并添加requestsMixin.js
。在文件中:
const APIURL = "http://localhost:3000";
const MEAL_DB_URL = "https://www.themealdb.com/api/json/v1/1/search.php?s=";
const axios = require("axios");
export const requestsMixin = {
methods: {
getGrocery() {
return axios.get(`${APIURL}/grocery`);
},
addGrocery(data) {
return axios.post(`${APIURL}/grocery`, data);
},
editGrocery(data) {
return axios.put(`${APIURL}/grocery`, data);
},
findDishes(keyword) {
return axios.get(`${MEAL_DB_URL}${keyword}`);
}
}
};
这些是我们在组件中使用的功能,用于发出HTTP请求以获取并保存我们的食品杂货数据并在Meal DB API中搜索菜肴。
接下来的中Home.vue
,将现有代码替换为:
<template>
<div class="page">
<h1 class="text-center">Grocery List</h1>
<b-button-toolbar class="button-toolbar">
<b-button
v-ripple.mouseover.500
@click="openAddModal()"
variant="primary"
>Add Ingredients to Grocery List</b-button>
</b-button-toolbar>
<h4>Your Grocery List</h4>
<b-list-group>
<b-list-group-item
v-for="(ingredient, i) of grocery.ingredients"
:key="i"
v-ripple.mouseover="'rgba(255, 255, 255, 0.35)'"
>
{{ingredient}}
<font-awesome-icon icon="times" class="float-right" @click="removeIngredient(i)" />
</b-list-group-item>
</b-list-group>
<b-modal id="add-modal" title="Add Ingredients to Grocery List" hide-footer>
<GroceryForm
@saved="closeModal()"
@cancelled="closeModal()"
:edit="false"
:groceryListId="grocery.id"
/>
</b-modal>
</div>
</template>
<script>
// @ is an alias to /src
import GroceryForm from "@/components/GroceryForm.vue";
import { requestsMixin } from "@/mixins/requestsMixin";
export default {
name: "home",
components: {
GroceryForm
},
mixins: [requestsMixin],
computed: {
grocery() {
return this.$store.state.grocery;
}
},
data() {
return {
ingredients: []
};
},
beforeMount() {
this.getGroceryList();
},
methods: {
openAddModal() {
this.$bvModal.show("add-modal");
},
closeModal() {
this.$bvModal.hide("add-modal");
},
async getGroceryList() {
const { data } = await this.getGrocery();
this.$store.commit("setGrocery", data);
},
async removeIngredient(index) {
this.ingredients.splice(index, 1);
const payload = { id: this.grocery.id, ingredients: this.ingredients };
await this.editGrocery(payload);
const { data } = await this.getGrocery();
this.$store.commit("setGrocery", data);
}
},
watch: {
grocery: {
handler(val) {
this.ingredients = val.ingredients || [];
},
deep: true,
immediate: true
}
}
};
</script>
};
这是主页的组件。我们在这里显示从后端获得的所选配料列表。另外,我们还有一个按钮来打开一个模式,该模式与GroceryForm
我们先前创建的一起添加到购物清单中。获取数据是在getGroceryList
函数中完成的。我们将获得的数据放在函数的最后一行中的Vuex存储中。
此外,我们还允许用户使用该removeIngredient
功能删除保存在此页面列表中的成分。我们调用从存储中的状态获得splice
的this.ingredients
数组,grocery
然后将其设置为handler
的watch
块中的当前值grocery
。
同样,我们使用Vue Ripple将波纹效果应用到按钮和列表行。v-ripple.mouseover.500
显示按钮和按钮500毫秒的涟漪效应v-ripple.mouseover=”’rgba(255, 255, 255, 0.35)’”
。像我们在中所做的那样,涟漪图将具有在列表项中指定的颜色GroceryForm
。
接下来的App.vue
,我们将现有代码替换为:
<template>
<div id="app">
<b-navbar toggleable="lg" type="dark" variant="info">
<b-navbar-brand to="/">Grocery List App</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-item to="/" :active="path == '/'">Home</b-nav-item>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<router-view />
</div>
</template>
<script>
export default {
data() {
return {
path: this.$route && this.$route.path
};
},
watch: {
$route(route) {
this.path = route.path;
}
}
};
</script>
<style lang="scss">
.page {
padding: 20px;
}
button,
.btn.btn-primary {
margin-right: 10px !important;
}
.button-toolbar {
margin-bottom: 10px;
}
</style>
这会将Bootstrap导航栏添加到页面顶部,并router-view
显示我们定义的路线。本style
部分不受范围限制,因此样式将在全球范围内应用。在.page
选择器中,我们向页面添加一些填充。我们在剩余style
代码中为按钮添加一些填充。
然后在中main.js
,将现有代码替换为:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import BootstrapVue from "bootstrap-vue";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
import { ValidationProvider, extend, ValidationObserver } from "vee-validate";
import { required, min_value, max_value } from "vee-validate/dist/rules";
import Ripple from "vue-ripple-directive";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { library } from "@fortawesome/fontawesome-svg-core";
import { faTimes } from "@fortawesome/free-solid-svg-icons";
library.add(faTimes);
Vue.component("font-awesome-icon", FontAwesomeIcon);
Vue.directive("ripple", Ripple);
extend("required", required);
Vue.component("ValidationProvider", ValidationProvider);
Vue.component("ValidationObserver", ValidationObserver);
Vue.use(BootstrapVue);
Vue.config.productionTip = false;
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
我们在此处添加了我们需要的所有库,包括BootstrapVue JavaScript和CSS,Vee-Validate组件以及验证规则,Vue-Ripple库和Vue Font Awesome软件包。使用Vue Font Awesome faTimes
的library.add
功能将其添加到我们的应用程序中,以便我们可以在我们的应用程序中使用它。
在router.js
我们将现有代码替换为:
import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
Vue.use(Router);
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
component: Home
}
]
});
这包括我们路线中的主页,以便用户可以看到该页面。
在中store.js
,我们将现有代码替换为:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
grocery: {}
},
mutations: {
setGrocery(state, payload) {
state.grocery = payload;
}
},
actions: {}
});
这增加了我们的杂货店状态到店,所以我们可以观察它在computed
块GroceryForm
和HomePage
组件。我们具有setGrocery
更新grocery
状态的功能,可以this.$store.commit(“setGrocery”, data);
像在GroceryForm
和中那样通过调用在组件中使用它HomePage
。
最后,index.html
我们将现有代码替换为:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title>Grocery List App</title>
</head>
<body>
<noscript>
<strong
>We're sorry but vue-ripple-tutorial-app doesn't work properly without
JavaScript enabled. Please enable it to continue.</strong
>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
这将更改我们应用的标题。
经过所有艰苦的工作,我们可以通过运行来启动我们的应用程序npm start
。
要开始后端,我们首先json-server
运行运行该软件包npm i json-server
。然后,转到我们的项目文件夹并运行:
json-server --watch db.json
在中db.json
,将文本更改为:
{
"grocery": {}
}
因此,我们grocery
在requests.js
可用项中定义了端点。
经过所有的努力,我们得到:
翻译自:https://levelup.gitconnected.com/how-to-add-font-awesome-icons-to-your-vue-js-app-3641831887fd
网友评论