上一篇文章还遗留了一个问题:

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中的importrequire了。

之前的错误就在于并没有引入资源文件,而是单纯的定义了一个字符串。就如同下面的代码,将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了。

 

 

Logo

前往低代码交流专区

更多推荐