使用Vue cli3搭建一个用Fetch Api的组件

系列参考 ,英文原文参考

 

我的git代码: https://github.com/chentianwei411/Typeahead


目标:

建立一个输入关键字得到相关列表的组件,用Vuejs2和Fetch API

思路:

把一个json数据,fetch到本地。然后用户模糊搜索title, 得到相关的结果列表。

[
  {
    "userId": 1,
    "id": 1,
    "title": "sunt aut facere repellat provident",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum"
  },
...

 

工具:

使用JSONPlaceholder上的json数据(一个Fake Online REST API用于测试和Prototyping Serving)

使用VueJs2建立一个简单的组件。

不会使用任何库,如Axios ,jQuery, 而使用原生的Fetch API.

使用VueCLI3来搭建手脚架项目。 

 

步骤:

1.安装Vue (参考之前的博客

yarn global add @vue/cli
vue --version         # 查看是否安装好!
vue create type.vue      # 新建一个项目,插件选择后,cd type.vue进入。
yarn serve            # 执行这条命令,打开热重载模式的网页,具体说明参考之前的博客。

  

2. 创建组件Typeahead。

在Aup.vue的<template>加上:

      <Typeahead
        source="https://jsonplaceholder.typicode.com/posts"
        placeholder="What Tv Serie you are looking for..."
        filter-key="title"
        :start-at="2"
      />

 

设置4个prop特性:

  • source接收源数据。
  • placeholder设置输入框的默认内容
  • filter-key设置搜索的关键字属于source data中的哪部分。
  • v-bind:start-at,这个是动态的绑定,用户在input内输入字符的个数最少是多少个才能展开搜索

⚠️:v-bind:start-at="2"告诉Vue,动态赋予一个表达式。虽然2是整数,但其实它是一个表达式。

 

另外,也可以增加非prop特性

一个非prop特性是给组件添加一个特性,但在组件的props定义中没有这个特性。

非prop特性会添加到这个组件的根元素上。

 

3. props接受父组件传入的数据。

数据来源的类型是array对象。

[
  {
    "userId": 1,
    "id": 1,
    "title": "sunt aut facere repellat provident",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum"
  },
...

 因此,prop至少有3个:

       props: {
            source: {
                type: [String, Array],
                required: true
            },
            filterKey: {
                type: String,
                required: true
            },
            startAt: {
                type: Number,
                default: 3
            },
       placeholder: {
         type: String,
         default: "",
       }

 

4. 然后建立model/state, 即VueJS的data。

此时我们将有2个特性, 给data对象。

<script>
    export default {
        data() {
            return {
                items: [],
                query: ''
            }
        }
    }
</script>

items数组用来保存从source prop传入的数据。

query是一个空string。它会和input标签绑定。使用v-mode指令。这样它会被实时的更新,无需刷新网页。

 

5. 在定义完model后,创建一个fetchItems方法来让items数组接收来自source prop的数据。

这个方法放入methods对象中。

<script>
    export default {
        methods: {
            fetchItems() {
                if ( typeof this.source === 'string' ) {
                    fetch(this.source)
                        .then(stream => stream.json())
                        .then(data => this.items = data)
                        .catch(error => console.error(error))
                } else {
                    this.items = this.source
                }
            }
        }
    }
</script>

这里有一个判断:

因为定义的source prop的type可能是string,也可能是array对象。

如果是string, 则使用Fetch API并把response的数据储存到items数组中。

如果用户手动传入的是array对象,则直接赋值给items.

 

fetch方法接收URL返回以promise对象。

第一个then把数据转化为json格式。

第二个then,则是涉及到实际的data,从服务器来的数据被分配给组件实例中的itmes数组。

还有catch方法,用于处理任何的错误。

 

6. 建立好fetchItems方法后,使用mounted 钩子函数,这样当组件挂载时,fetchItems被激发。

 

7. 现在设置Vue component的template部分。

增加一个input标签,query特性绑定v-model。

当在input中输入一个关键字时,会查找items中每个item对象中的body。并列出搜索到的item。

一个假设,输入框要求用户输入想要查询的文章的部分title,即能显示查询的相关记录。

所以之前用filterKey prop来储存item对象中的property。

 

8. 使用computed 特性。这是reactive响应式的。

定义一个filtered函数:

  • 1. 当字符输入大于startAt prop,则继续,否则退出filtered函数。
  • 2.对items的每个item进行验证,使用Array.protptype.filter()方法,这会生成一个新的array,内含符合filter内函数判断为true的item.
      •     computed: {
              filtered() {
                if (this.query.length > this.startAt) {
                  return this.items.filter(item => {
                       //
                  })
                }
              }
            }
  • 3. filter()内的函数:这里有一个假设,用户搜索的是item中的某个key的值:这里用filterKey来存储这个key。因此使用item.hasOwnProperty(this.filterKey)作为if的条件
    • 如果if false则console.error(`...${...}...`)。输出到控制台某个提示❌信息。
  • 4. 最后,我们会检查这个item的filterKey的值,看它是否和用户输入的query互相匹配。
    • 这里有2个方法:
    • 1. 使用javascript中的正则表达式构建器进行匹配。
    • 2. 或者使用indexOf()方法。string.indexOf("xxx")会返回“xxx”所处的位置,一个整数它必大于-1。所以可以使用 string.indexOf("xxx") > -1的方式进行条件判断。
  • 另外,取消大小写的判断,用toLowerCase()来转为小写字符。

 

9. 现在filtered函数会返回符合用户输入条件的items对象集合(数组)。

让我们把这些数据,显示在网页上,修改template模版。添加:

<ul>
    <li v-for="item in filtered"  v-bind:key="item.id">
        //... 
    </li>
</ul>

 

为了能够使用过渡动画效果,可以用css自己写,但是有现成的工具,就无需自己再造轮子了(一个梗😄)。使用Vuejs自带的<transition-group>,各种效果都可以实现具体看官方文档过渡&动画

        <transition-group name="fade" tag="ul" class="Results">
            <li v-for="item in filtered" :key="item">
                <span>
                    <strong>{{ item.title  }}</strong> - <small>{{ item.id  }}</small><br>
                    <small>{{ item.body  }}</small>
                </span>
            </li>
        </transition-group>

<transition-group>用于多个元素/组件的过渡效果。它渲染真实的DOM元素。

tag属性配置哪个元素应该被渲染,默认<span>.

name属性用于生成*-enter, *-leave-to等6个过渡的类名,默认是v-[enter|leave]-*

 

在<style>中加上对应的类:

  .SearchInput {
    width: 100%;
    padding: 1.5em 1em;
    font-size: 1em;
    outline: 0;
    border: 5px solid #41B883;
  }
  .Results {
    margin: 0;
    padding: 0;
    text-align: left;
    position: relative;
  }
  .Results li {
    background: rgba(53, 73, 94, 0.3);
    margin: 0;
    padding: 1em;
    list-style: none;
    width: 100%;
    border-bottom: 1px solid #394E62;
    transition: ease-in-out 0.5s;   #一个平滑的过渡设置。
  }

#让开始到结束的整个过渡阶段,产生过渡效果。 .fade
-enter-active, .fade-leave-active { transition: opacity 0.3s; }

#让开始(在元素被插入前生效)和结束(离开过渡被触发后的下一桢生效)不使用透明效果。(2个瞬间状态。)
.fade-enter, .fade-leave-to { opacity: 0; }

 

 

10.如果filtered函数没返回满足用户输入的条件的结果。

我们需要显示一条提示信息告诉用户没有相关内容。

还是使用computed特性添加一个isEmpty函数:

<script>
    export default {
        computed: {
            isEmpty() {
                if( typeof this.filtered === 'undefined'  ) {
                    return false
                } else {
                    return this.filtered.length < 1
                }
            }
        }
    }
</script>

解释:

用户没有输入的时候,this.filtered === "undefined", 不会显示提示信息。

如果用户输入信息后,没有找到记录则this.filtered.length < 1, 返回true,显示提示信息!

 

然后把这个computed特性中的isEmpty函数集成到template中:我们使用v-show命令来检查我们的。

<p v-show="isEmpty">Sorry, but we can't find any match for given term :( </p>

 

当有搜索结果后,用户可能做其他操作,比如点击出现的记录的链接,或者做些别的什么,这时程序可以清空<input>输入框。

在methods对象中添加一个reset()函数, this.query = ""

当<input>失去焦点时,激活reset()。用javaScript自带的Onburl event

        <input 
            v-model="query"
            @blur="reset"

 

最后的操作,把完成的组件集成到应用程序。

打开App.vue文件,这是由VueCLI3自动生成的。

改成这个样子:

<template>
    <div id="app">
         <div class="Wrap text-center">
             <h1>Vue Typeahead</h1>
             <p>Simple VueJS 2 TypeAhead component builded with Fetch Browser API.</p>

             <!-- Our component-->
             <typeahead
                source="https://jsonplaceholder.typicode.com/posts"
                placeholder="What TV Serie you are looking for..."
                filter-key="title"
                :start-at="2"
             >
             </typeahead>   
         </div>
    </div>
</template>

<script>

    import Typeahead from './components/Typeahead.vue'

    export default {

        name: 'app',

        components: { Typeahead  }

    }

</script>

<style>
    body {
        margin: 0; padding: 0;
        font-family: 'Open Sans', Arial, sans-serif;
        box-sizing: border-box;
        background: linear-gradient(135deg, #41B883 0%,#354953 100%);
        background-size: cover;
        min-height: 100vh;
        color: #fff;
    }
    h1 {
        font-size: 6vw;
    }
    h1, h2, h3, h4 {
        margin: 0; padding: 0;
        font-family: 'Lobster', Arial, sans-serif;
    }
    .text-center {
        text-align: center;
    }
    .Wrap {
        max-width: 60vw;
        margin: 15vh auto;
    }
</style>

 
#
linear-gradient(方向,开始颜色,结束颜色)是一个设置背景色的函数:用它可以产生不同方向的颜色渐变背景。
  • 方向: 定义一个开始点和gradient效果的方向
  • 开始颜色, 想渲染的平滑过渡的颜色,可以附加一个百分数,即从什么比例的位置开始过渡。
  • 结束颜色, 附加的百分数,决定过渡效果的结束点

总结:

如何创建一个简单的输入查询组件,并使用Fetch Api。其中使用VueJs中的常用功能,如props传入数据,使用computed properties创建,组织你的Vue程序。

 


 

 

附加git commit骚操作

修改了多次git 的readme. 让提交变得有点乱,所以想把所有readme的操作合并成一个commit。

1. git reset Head~3    (回退几步操作)

2.因为修改的代码是正确的所以 git stash

3.打开sourcetree, 树结构一看就明白。

git rebase -i [目标提交点]    (即在这个提交点后的提交点重新排序)

4. 然后再git stash pop,  拿出之前放入stash的文件。

5. 最后git commit --amend, 👌

6. 附加: 强制push到个人的远程仓库上

git push -f

 

posted @ 2018-12-12 10:03  Mr-chen  阅读(1262)  评论(0编辑  收藏  举报