跟着项目学vue.js(八) 准备布局页(下)
上一篇文章还遗留了一个问题:Footer.vue中的底部导航不应该是静态的DOM,而是应该将定义好的导航数据循环绑定到视图模板中。单页组件由三部分组成:<template>——视图模板<style>——组件样式表<script>——组件定义其中组件脚本定义中使用data定义用于内部访问的数据模型,而视图模板基于DO
上一篇文章还遗留了一个问题:
Footer.vue中的底部导航不应该是静态的DOM,而是应该将定义好的导航数据循环绑定到视图模板中。
单页组件由三部分组成:
<template>——视图模板
<style>——组件样式表
<script>——组件定义
其中组件脚本定义中使用data定义用于内部访问的数据模型,而视图模板基于DOM实现,使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。这两者结合,正可以满足我们的需求。
1、组件定义使用data定义一个数组【Menus】,包含name,href,icon和ison。
<script>
import Vue from 'vue';
import { Tabbar, TabbarItem } from 'we-vue';
Vue.use(Tabbar).use(TabbarItem);
export default {
data() {
return {
Menus: [
{ name: '首页', href: '/', icon: '../../assets/icon_tabbar.png', ison: true },
{ name: '所有商品', href: '/products', icon: '../../assets/icon_tabbar.png', ison: false },
{ name: '购物车', href: '/cart', icon: '../../assets/icon_tabbar.png', ison: false },
{ name: '我', href: '/profile', icon: '../../assets/icon_tabbar.png', ison: false },
]
}
}
};
</script>
这里的Menus是我们自己定义的测试数据,而真实数据应该是通过调用后端提供的Restful服务获取的。但是现在这个时间点,服务还在整合当中,我们只能自己定义一些测试数据,以便将工作往下进行。
2、 清空视图模板中的底部选项卡
<template>
<div>
<wv-tabbar :fixed="true">
</wv-tabbar>
</div>
</template>
现在底部已经空空如也了 :
3、在视图模板中通过模板语法绑定数据【Menus】
这是之前的选项卡的项内容
<img class="weui-tabbar__icon" src="../../assets/icon_tabbar.png" slot="icon">首页
通过观察之前的代码,可以发现底部选项卡的项内容中【首页】是一个文本,对应数据中的name,而src是一个HTML特性,对应数据中的【icon】。
数据绑定最常见的形式就是使用Mustache 语法的 {{...}}(双大括号)的文本插值:
<template>
<div>
<wv-tabbar :fixed="true">
<wv-tabbar-item to="/" is-on>
{{Menus[0].name}}
</wv-tabbar-item>
</wv-tabbar>
</div>
</template>
保存后,成功显示出项内容【首页】
我们依样画葫芦,插入icon:
<img class="weui-tabbar__icon" src="{{Menus[0].icon}}" slot="icon">{{Menus[0].name}}
保存之后,却发生如下错误:
通过有道翻译得知,属性内的插值已被删除,使用v-bind或冒号速记代替 。
即在现在的版本中,Mustache 语法不能作用在 HTML 特性上,遇到这种情况应该使用v-bind指令代替,v-bind可以简写成冒号。
<template>
<div>
<wv-tabbar :fixed="true">
<wv-tabbar-item v-bind:to="Menus[0].href" is-on>
<img class="weui-tabbar__icon" v-bind:src="Menus[0].icon" slot="icon">
{{Menus[0].name}}
</wv-tabbar-item>
</wv-tabbar>
</div>
</template>
图片并没有成功显示出来,但是顶部的logo却成功显示,这说明当img的src属性变成动态渲染时出了问题。
浏览器中F5查看源代码,对比二者的区别:
Logo:
TabbarItem:
Logo中的src是Webpack打包之后的路径。我的猜想是Webpack会把工程里可以识别的图片路径打包到img文件夹下,比如<template>中的logo路径,而我们把路径定义在<script>内,它只是js里的一个字符串。为了印证这一点,需要查看webpack中的具体配置:
1)脚手架中有一个inspect功能,用于检查webpack配置。
点击变量按钮,环境选择development并保存。
2)点击运行按钮,会输出完整的webpack配置
3)全文检索关键字"img/",发现只在下面这个方法中有过出现。
config.module.rule('images')
{
test: /\.(png|jpe?g|gif|webp)(\?.*)?$/,
use: [
config.module.rule('images').use('url-loader')
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
}
}
}
}
]
},
工程中被引入的满足上面正则表达式的四种后缀的资源文件,都会通过【url-loader】工具的处理,如果不超过4096字节会被转换成Base64编码,超出这个限制则会被打包在img文件夹下。
这里的【被引入】可以是html和css中的url和src等,当然还有js中的import和require了。
之前的错误就在于并没有引入资源文件,而是单纯的定义了一个字符串。就如同下面的代码,将img标签的src改成class,是不会被处理的。
<img class="../../assets/icon_tabbar.png" />
4)将数组内的路径Require一下:
<script>
import Vue from 'vue';
import { Tabbar, TabbarItem } from 'we-vue';
Vue.use(Tabbar).use(TabbarItem);
const icon = require('../../assets/icon_tabbar.png');
export default {
data() {
return {
Menus: [
{ name: '首页', href: "/", icon, ison: true },
{ name: '所有商品', href: "/products", icon, ison: false },
{ name: '购物车', href: "/cart", icon, ison: false },
{ name: '我', href: "/profile", icon, ison: false },
]
}
}
};
</script>
保存之后,界面如下,图片已经可以显示了:
5)查看源代码,图片被转换为Base64编码:
即Webpack将我们的require('路径')转换成了base64。大概过程如下:
const icon = require('../../assets/icon_tabbar.png');
如果图片小于4096字节,则替换成base64编码
const icon = 'data:iamge/png;base64,......';
否则,会将图片打包到img文件夹下重命名成icon_tabbar.混淆.png,并将该语句替换成路径
const icon = '/img/icon_tabbar.混淆.png';
PS:在线上,图片是通过服务获取的远程路径或者Base64,避开了这种情况。即使是真正的本地图片,很大肯能上会用后端配置好的web服务器路径,也避开了这种情况。但这些都是建立在服务已经提供好,或者后端配置好Web服务器的前提下,对开发来说意义不大。
一是因为纯静态网站根本就涉及不到后端的,上面的方案都不会被考虑,能依靠的只有Webpack,如果不把刚才的踩一遍,只能说明你连开发纯静态网站的能力都没有。
二是即便不是静态网站,那除非你想等后端把所有工作完成之后才开始工作,不过很显然,这不现实。
在前期的开发过程中,所有的网站都是静态网站。
4、使用循环语句绑定整个数组
循环使用 v-for 指令,需要以 site in sites 形式的特殊语法,来绑定数据到数组来渲染一个列表:
<template>
<div>
<wv-tabbar :fixed="true">
<wv-tabbar-item v-bind:to="menu.href" :is-on="menu.ison" v-for="menu in Menus">
<img class="weui-tabbar__icon" v-bind:src="menu.icon" slot="icon">{{menu.name}}
</wv-tabbar-item>
</wv-tabbar>
</div>
</template>
<script>
import Vue from 'vue';
import { Tabbar, TabbarItem } from 'we-vue';
Vue.use(Tabbar).use(TabbarItem);
const icon = require('../../assets/icon_tabbar.png');
export default {
data() {
return {
Menus: [
{ name: '首页', href: "/", icon, ison: true },
{ name: '所有商品', href: "/products", icon, ison: false },
{ name: '购物车', href: "/cart", icon, ison: false },
{ name: '我', href: "/profile", icon, ison: false },
]
}
}
};
</script>
保存之后,结果如下:
5、查看vue ui 中的输出,虽然成功运行,但是产生了61个error,大部分是格式问题
进入lint页,并点击运行按钮进行修复
现在只剩一个error了,输出内容如下,即在使用v-for时,必须添加唯一的key
error: Custom elements in iteration require 'v-bind:key' directives (vue/valid-v-for)
我们这里用数组下标index来作为key
<template>
<div>
<wv-tabbar :fixed="true">
<wv-tabbar-item :to="menu.href" :is-on="menu.ison" v-for="(menu,index) in Menus" :key="index">
<img class="weui-tabbar__icon" v-bind:src="menu.icon" slot="icon">{{menu.name}}
</wv-tabbar-item>
</wv-tabbar>
</div>
</template>
<script>
import Vue from 'vue';
import { Tabbar, TabbarItem } from 'we-vue';
Vue.use(Tabbar).use(TabbarItem);
const icon = require('../../assets/icon_tabbar.png');
export default {
data() {
return {
Menus: [
{
name: '首页', href: '/', icon, ison: true,
},
{
name: '所有商品', href: '/products', icon, ison: false,
},
{
name: '购物车', href: '/cart', icon, ison: false,
},
{
name: '我', href: '/profile', icon, ison: false,
},
],
};
},
};
</script>
保存之后,查看vue ui中的输出:
使用
v-for
更新已渲染的元素列表时列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素;在需要频繁插入和删除元素的数组中,元素的下标也会随之变动,因此也不适合使用数组下标作为key。这时就需要要求Restful服务中给我们提供这个key了。
更多推荐
所有评论(0)