06-文章搜索页面

news2025/1/11 20:39:23

文章搜索页面

6-1:开篇

再上一章中,我们完成了 热搜首页 的开发,虽然经历了 ”千辛万苦“ ,但是对大家来说,应该也是收获满满。

那么在这一章节,我们将会进入新的篇章,来到 文章搜索 页面的开发。那么在 文章搜索 的页面开发中,我们又会经历哪些 奇奇怪怪的 bug ,又将会获得哪些新的收获呢?

让我们一起期待吧!

6-2:文章搜索 - 分析文章搜索页面

  1. 【慕课热搜】
    1. 展示 8 个热搜内容
  2. 【搜索历史】
    1. 按照【从后向前】的顺序,展示搜索历史
    2. 点击【小垃圾筒】可删除历史记录
  3. 【搜索结果】
    1. 不输入内容直接回车,按照当前的 placeholder 索引
    2. 输入内容,按照当前内容索引
    3. item 的展示分为三类
      1. 无图片展示
      2. 单个图片展示
      3. 三个图片展示
    4. item 中关键字高亮
    5. 点击 【叉号】返回【搜索历史】
    6. 点击【取消】返回【慕课热搜】

6-3:文章搜索 - 使用分包,创建 search-blog 页面

分包

  1. 什么是分包

    分包指:将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载

  2. 分包的好处

    • 可以优化小程序首次启动的下载时间
    • 在多团队共同开发时可以更好的解耦协作

微信小程序 提供了分包的能力,而 uniapp 也对其进行了支持。

实现分包

  1. 打开 pages.json,新建 subPackages 节点

    "subPackages": []
    
  2. 节点中每个对象为一个分包,其中

    1. root:分包包名
    2. name:分包别名
    3. pages:分包下的页面
      1. path:分包下的页面路径
      2. style:页面的样式
  3. "subPackages": [
        {
          "root": "subpkg",
          "name": "sub-1",
          "pages": [
            {
              "path": "pages/search-blog/search-blog",
              "style": {
                "navigationBarTitleText": "",
                "enablePullDownRefresh": false
              }
            }
          ]
        }
      ]
    

    可在详情查看分包数据:
    请添加图片描述

6-4:文章搜索 - 完成跳转,渲染搜索框

页面跳转

<template>
  <view class="hot-container">
    <view class="search-box" @click="onToSearch">
      <!-- 搜索模块 -->
      <my-search placeholderText="uni-app 自定义组件" />
    </view>
  </view>
</template>

<script>
import { getHotTabs, getHotListFromTabType } from 'api/hot';
export default {
  // 定义方法
  methods: {
    ...
    /**
      搜索框点击事件
     */
    onToSearch() {
      uni.navigateTo({
        url: '/subpkg/pages/search-blog/search-blog'
      });
    }
  }
};
</script>

渲染搜索框

<template>
  <view class="search-blog-container">
    <!-- search模块 -->
    <view class="search-bar-box">
      <my-search />
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {};
  }
};
</script>

<style lang="scss" scoped>
.search-blog-container {
  .search-bar-box {
    background-color: $uni-bg-color;
    padding: $uni-spacing-row-sm;
    position: sticky;
    top: 0px;
    z-index: 9;
  }
}
</style>

6-5:文章搜索 - 为 my-search 组件赋予搜索的能力

my-search

<template>
  <view class="my-search-container">
    <!-- 搜索输入框 -->
    <uni-search-bar
      v-if="isShowInput"
      class="my-search-bar"
      :radius="100"
      @confirm="onSearch"
      @focus="onFocus"
      @blur="onBlur"
      @clear="onClear"
      @cancel="onCancel"
      @input="onInput"
      :bgColor="config.backgroundColor"
      :placeholder="placeholderText"
      :value="value"
    >
      <uni-icons slot="clearIcon" type="clear" color="#999999" />
    </uni-search-bar>
    <!-- 搜索按钮 -->
    <view class="my-search-box" v-else>
      ...
    </view>
  </view>
</template>

<script>
export default {
  name: 'my-search',
  props: {
    // placeholder
    placeholderText: {
      type: String,
      default: '搜索'
    },
    // 配置对象
    config: {
      type: Object,
      default: () => ({
        height: 36,
        backgroundColor: '#ffffff',
        icon: '/static/images/search.png',
        textColor: '#454545',
        border: '1px solid #c9c9c9'
      })
    },
    // 是否显示输入框
    isShowInput: {
      type: Boolean,
      default: false
    },
    // 输入的内容
    // value 名称不可修改,与 $emit('input') 事件对应
    value: {
      type: String
    }
  },
  data() {
    return {};
  },
  methods: {
    /**
     * 点击搜索按钮触发
     */
    onSearch() {
      this.$emit('search', this.value);
    },
    /**
     * 输入框获取焦点触发
     */
    onFocus() {
      this.$emit('focus', this.value);
    },
    /**
     * 输入框失去焦点触发
     */
    onBlur() {
      this.$emit('blur', this.value);
    },
    /**
     * 点击输入框中的清空按钮时
     */
    onClear() {
      this.$emit('clear', this.value);
    },
    /**
     * 点击取消按钮时
     */
    onCancel() {
      this.$emit('cancel', this.value);
    },
    /**
     *  value 改变时触发事件
     */
    onInput(val) {
      // input 的事件名称不可修改,与 props 中的 value 对应
      // 当同时存在:
      // props -> value
      // $emit('input', val)
      // 时,在组件外可以使用 v-model 完成双向数据绑定。
      // 即:用户输入内容时,父组件传递过来的 value 同步发生变化
      // 详细见 vue 中 v-model 指令:https://cn.vuejs.org/v2/guide/components-custom-events.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6%E7%9A%84-v-model
      this.$emit('input', val);
    }
  }
};
</script>

<style lang="scss" scoped>
.my-search-container {
  display: flex;
  align-items: center;
  .my-search-bar {
    width: 100%;
  }
  ...
}
</style>

search-blog.vue

<template>
  <view class="search-blog-container">
    <!-- search模块 -->
    <view class="search-bar-box">
      <my-search
        :placeholderText="defaultText"
        v-model="searchVal"
        :isShowInput="true"
        :config="{
          backgroundColor: '#f1f0f3'
        }"
        @search="onSearchConfirm"
        @focus="onSearchFocus"
        @blur="onSearchBlur"
        @clear="onSearchClear"
        @cancel="onSearchCancel"
      />
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      // 绑定输入框中的内容
      searchVal: '',
      // 默认的placeholderText
      defaultText: '默认的placeholderText'
    };
  },
  methods: {
    /**
     * 搜索内容
     */
    onSearchConfirm(val) {
      console.log('搜索内容:' + this.searchVal);
    },
    // searchbar 获取焦点
    onSearchFocus(val) {
      console.log('searchbar 获取焦点');
    },
    /**
     * searchbar 失去焦点
     */
    onSearchBlur(val) {
      console.log('searchbar 失去焦点');
    },
    /**
     * searchbar 清空内容
     */
    onSearchClear() {
      console.log('searchbar 清空内容');
    },
    /**
     * searchbar 取消按钮
     */
    onSearchCancel(val) {
      console.log('searchbar 取消按钮');
    }
  }
};
</script>

<style lang="scss" scoped>
.search-blog-container {
  .search-bar-box {
    background-color: $uni-bg-color;
    padding: $uni-spacing-row-sm;
  }
}
</style>

因为 uni-search-bar 组件没有提供 文本居左的属性,所以想要让文本居左显示,需要修改 uni-search-bar 的源代码:

.uni-searchbar__box {
  // 处理初始 searchbar 位置
  justify-content: start;
}

6-6:文章搜索 - 显示推荐搜索

api/search.js

import request from '../utils/request';

/**
 * 默认搜索内容
 */
export function getDefaultText() {
  return request({
    url: '/search/default-text'
  });
}

search-blog.vue

  created() {
    this.loadDefaultText();
  },
  methods: {
    /**
     * 获取推荐搜索文本
     */
    async loadDefaultText() {
      const { data: res } = await getDefaultText();
      this.defaultText = res.defaultText;
    }
   }

6-7:文章搜索 - 创建三个业务组件

search-blog.vue

    <!-- 热搜列表 -->
    <view class="search-hot-list-box">
      <!-- 列表 -->
      <search-hot-list />
    </view>
    <!-- 搜索历史 -->
    <view class="search-history-box">
      <search-history />
    </view>
    <!-- 搜索结果 -->
    <view class="search-result-box">
      <search-result-list />
    </view>

6-8:文章搜索 - 控制业务组件的展示效果

<template>
  <view class="search-blog-container">
    ...
    <!-- 热搜列表 -->
    <view class="search-hot-list-box" v-if="showType === HOT_LIST">
      <!-- 列表 -->
      <search-hot-list />
    </view>
    <!-- 搜索历史 -->
    <view class="search-history-box" v-else-if="showType === SEARCH_HISTORY">
      <search-history />
    </view>
    <!-- 搜索结果 -->
    <view class="search-result-box" v-else>
      <search-result-list />
    </view>
  </view>
</template>

<script>
import { getDefaultText } from 'api/search';
// 0: 热搜列表 - 默认
const HOT_LIST = '0';
// 1:搜索历史
const SEARCH_HISTORY = '1';
// 2:搜索结果
const SEARCH_RESULT = '2';
export default {
  data() {
    return {
      HOT_LIST,
      SEARCH_HISTORY,
      SEARCH_RESULT,
      // 默认情况下 || 点击输入框的取消按钮时,显示【热搜列表】
      // 当 searchBar 获取焦点时 || 点击输入框清空按钮时,显示 【搜索历史】
      // 用户点击热搜列表 item || 用户点击搜索历史 || 用户按下搜索键,显示 【搜索结果】
      showType: HOT_LIST,
    };
  },
  methods: {
    ...
    /**
     * 搜索内容
     */
    onSearchConfirm(val) {
      // 用户未输入文本,直接搜索时,使用【推荐搜索文本】
      this.searchVal = val ? val : this.defaultText;
      if (this.searchVal) {
        this.showType = SEARCH_RESULT;
      }
    },
    // searchbar 获取焦点
    onSearchFocus(val) {
      this.showType = SEARCH_HISTORY;
    },
    /**
     * searchbar 失去焦点
     */
    onSearchBlur(val) {},
    /**
     * searchbar 清空内容
     */
    onSearchClear() {
      this.showType = SEARCH_HISTORY;
    },
    /**
     * searchbar 取消按钮
     */
    onSearchCancel(val) {
      this.showType = HOT_LIST;
    }
  }
};
</script>

6-9:热搜列表 - 数据获取

api/search.js

/**
 * 热搜搜索列表
 */
export function getSearchHotList() {
  return request({
    url: '/search/hot-list'
  });
} 	

search-hot-list.vue


<script>
import { getSearchHotList } from 'api/search';

export default {
  name: 'search-hot-list',
  data() {
    return {
      hotList: []
    };
  },
  created() {
    this.getSearchHotList();
  },
  methods: {
    /**
     * 获取热搜列表数据
     */
    async getSearchHotList() {
      const { data: res } = await getSearchHotList();
      this.hotList = res.list;
      console.log(this.hotList);
    }
  }
};
</script>

6-10:热搜列表 - 数据展示

search-blog.vue

<!-- 热搜列表 -->
    <view class="search-hot-list-box card" v-if="showType === HOT_LIST">
      <!-- 列表 -->
      <search-hot-list />
    </view>

styles/global.scss

// 卡片视图
.card {
  border: 1px solid #f9f9f9;
  border-radius: 5px;
  margin: 12px;
  padding: 12px;
  box-shadow: 2px 2px 5px 1px rgba(143, 143, 143, 0.1);
}

search-hot-list.vue

<template>
  <view class="search-hot-list-container">
    <!-- 标题 -->
    <view class="search-hot-title">慕课热搜 - 全网技术 一网打尽</view>
    <block v-for="(item, index) in hotList" :key="index">
      <view class="search-hot-item" >
        <!-- 序号 -->
        <hot-ranking :ranking="index + 1"></hot-ranking>
        <!-- 文本 -->
        <text class="title line-clamp">{{ item.label }}</text>
        <!-- hot-icon -->
        <image v-if="index <= 2" class="search-hot-icon" src="/static/images/hot-icon.png" />
      </view>
    </block>
  </view>
</template>

<script>
</script>

<style lang="scss" scoped>
.search-hot-list-container {
  .search-hot-title {
    font-weight: bold;
    font-size: $uni-font-size-base;
    color: $uni-text-color-hot;
    padding: 0 12px $uni-spacing-col-lg 12px;
    margin: 0 -12px $uni-spacing-col-lg -12px;
    box-shadow: 2px 2px 5px 1px rgba(143, 143, 143, 0.1);
  }
  .search-hot-item {
    display: flex;
    align-items: center;
    padding: $uni-spacing-col-lg 0;
    .title {
      color: $uni-text-color;
      font-size: $uni-font-size-base;
      margin: 0 $uni-spacing-row-base;
    }
    .search-hot-icon {
      width: 14px;
      height: 14px;
    }
  }
}
</style>

6-11:热搜列表 - 热搜点击处理

search-hot-list.vue

<template>
  ...
      <view class="search-hot-item" @click="onItemClick(item, index)">
        ...
      </view>
  ...
</template>

<script>
...
export default {
  ...
  methods: {
    ...
    /**
     * item 点击事件
     */
    onItemClick(item, index) {
      this.$emit('onSearch', item.label);
    }
  }
};
</script>

search-blog.vue

<template>
  <view class="search-blog-container">
    ...
    <!-- 热搜列表 -->
    <view class="search-hot-list-box card" v-if="showType === HOT_LIST">
      <!-- 列表 -->
      <search-hot-list @onSearch="onSearchConfirm" />
    </view>
    ...
  </view>
</template>

<script>
...
export default {
  ...
  methods: {
    ...
    /**
     * 搜索内容
     */
    onSearchConfirm(val) {
      // 用户未输入文本,直接搜索时,使用【推荐搜索文本】
      this.searchVal = val ? val : this.defaultText;
      if (this.searchVal) {
        this.showType = SEARCH_RESULT;
      }
    },
    ...
  }
};
</script>
...

6-12:搜索历史 - 渲染基本结构

search-history.vue

<template>
  <view class="search-history-container">
    <!-- title 区域 -->
    <view class="search-history-title-box">
      <view class="search-history-title">搜索历史</view>
      <view v-if="!isShowClear">
        <uni-icons type="trash" @click="isShowClear = true" />
      </view>
      <view v-else>
        <text class="txt">全部删除</text>
        <text class="txt" @click="isShowClear = false">完成</text>
      </view>
    </view>
    <!-- 内容区域 -->
    <view class="search-history-box">
      <block v-for="(item, index) in searchData" :key="index">
        <view class="search-history-item">
          <text class="history-txt line-clamp">{{ item }}</text>
          <uni-icons v-show="isShowClear" type="clear" />
        </view>
      </block>
    </view>
  </view>
</template>

<script>
export default {
  name: 'search-history',
  data() {
    return {
      isShowClear: false,
      searchData: ['sunday', 'uniapp', 'vue', '前端']
    };
  }
};
</script>

<style lang="scss" scoped></style>

6-13:搜索历史 - 美化基本样式

search-history.vue

<style lang="scss" scoped>
.search-history-container {
  padding: $uni-spacing-col-lg $uni-spacing-row-lg;
  .search-history-title-box {
    display: flex;
    justify-content: space-between;

    .search-history-title {
      font-size: $uni-font-size-sm;
      color: $uni-text-color;
      padding: $uni-spacing-col-sm $uni-spacing-row-sm;
    }
    .txt {
      color: $uni-text-color-grey;
      font-size: $uni-font-size-sm;
      padding: $uni-spacing-col-sm $uni-spacing-row-sm;
    }
  }
  .search-history-box {
    margin-top: $uni-spacing-col-lg;
    .search-history-item {
      width: 50%;
      box-sizing: border-box;
      display: inline-block;
      padding: $uni-spacing-col-base $uni-spacing-row-base;
      position: relative;
      .history-txt {
        width: 85%;
        display: inline-block;
        color: $uni-text-color;
        font-size: $uni-font-size-base;
      }
    }
    .search-history-item:nth-child(odd):before {
      content: ' ';
      border-left: 1px solid #999;
      display: inline-block;
      height: 10px;
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      right: 0;
    }
  }
}
</style>

6-14:搜索历史 - 保存历史数据到 searchData

search-history.vue

onSearchConfirm 被回调时,将赋值之后的 this.searchVal 保存到 searchData 中。

所以我们需要对代码进行一些修改,把 searchDatasearch-history 中转移到 search-blog

search-blog

<template>
  <view class="search-blog-container">
    <!-- search模块 -->
    <view class="search-bar-box">
     ...
    <!-- 搜索历史 -->
    <view class="search-history-box" v-else-if="showType === SEARCH_HISTORY">
      <search-history :searchData="searchData" />
    </view>
    ...
  </view>
</template>

<script>
...
export default {
  data() {
    return {
      ...
      // 搜索历史数据
      searchData: []
    };
  },
  ...
  methods: {
    ...
    /**
     * 搜索内容
     */
    onSearchConfirm(val) {
      // 用户未输入文本,直接搜索时,使用【推荐搜索文本】
      this.searchVal = val ? val : this.defaultText;
      // 保存搜索历史数据
      this.saveSearchData();
      // 切换视图
      ...
    },
    /**
     * 保存搜索历史数据
     */
    saveSearchData() {
      // 1. 如果数据已存在,则删除
      const index = this.searchData.findIndex((item) => item === this.searchVal);
      if (index !== -1) {
        this.searchData.splice(index, 1);
      }
      // 2. 新的搜索内容需要先于旧的搜索内容展示
      this.searchData.unshift(this.searchVal);
    },
  }
};
</script>

search-history

<script>
export default {
  name: 'search-history',
  props: {
    searchData: {
      type: Array,
      required: true
    }
  },
  data() {
    return {
      isShowClear: false
    };
  }
};
</script>

6-15:搜索历史 - 处理 searchData 的删除操作

删除分为两种:

  1. 删除指定数据
  2. 删除全部数据

search-history

<template>
  <view class="search-history-container">
    <!-- title 区域 -->
    <view class="search-history-title-box">
      ...
      <view v-else>
        <text class="txt" @click="onClearAll">全部删除</text>
        ...
      </view>
    </view>
    <!-- 内容区域 -->
    <view class="search-history-box">
      <block v-for="(item, index) in searchData" :key="index">
        <view class="search-history-item" @click="onHistoryItemClick(item, index)">
          ...
        </view>
      </block>
    </view>
  </view>
</template>

<script>
export default {
 ...
  methods: {
    onClearAll() {
      uni.showModal({
        title: '提示',
        content: '删除搜索历史记录?',
        showCancel: true,
        success: ({ confirm, cancel }) => {
          if (confirm) {
            // 删除 searchData
            this.$emit('removeAllSearchData');
            // 返回状态
            this.isShowClear = false;
          }
        }
      });
    },
    onHistoryItemClick(item, index) {
      if (this.isShowClear) {
        // 删除指定的 searchData
        this.$emit('removeSearchData', index);
      } else {
        this.$emit('onItemClick', item);
      }
    }
  }
};
</script>

search-history

<template>
  <view class="search-blog-container">
    ...
    <!-- 搜索历史 -->
    <view class="search-history-box" v-else-if="showType === SEARCH_HISTORY">
      <search-history
        :searchData="searchData"
        @removeAllSearchData="onRemoveAllSearchData"
        @removeSearchData="onRemoveSearchData"
        @onItemClick="onSearchConfirm"
      />
    </view>
   ...
  </view>
</template>

<script>
...
export default {
  ... 
  methods: {
    ...
    /**
     * 删除数据
     */
    onRemoveSearchData(index) {
      this.searchData.splice(index, 1);
    },
    onRemoveAllSearchData() {
      this.searchData = [];
    },
    ...
  }
};
</script>

...

6-16:搜索历史 - 找出现在的问题

到目前,我们已经完成了 搜索历史 的展示和删除的功能,但是还有一个 数据持久化 的功能未实现。

未实现的功能我们先不着急,我们先回头看一下我们现在的代码。

在现在的代码中,我们在 search-blog 中通过 searchData 保存了所有的搜索历史数据。

而在真正的搜索历史页面中,反而是通过 props 接收了 父组件传递过来的数据。

添加、删除搜索历史的功能,都放到了 search-blog 页面里进行了实现,反而把 删除的激活 操作放到了 search-history 组件中。

这样的一系列操作,我们光描述都要花费上 一分钟 的时间,更不用说让别人去读你的代码了。

如果我们在这样的代码基础之上,再去实现 数据持久化 的功能,那么咱们的代码就会的更加复杂,难以理解了。

所以说,我们现在迫切需要做一件事情,那就是:search-blogsearch-history 解耦,让 searchData 和 组件 解耦 !

那么这个事情,我们怎么做呢?

这里请允许我先卖一个关子。

欲知后事如何,请见下一章**《全局状态管理》**

6-17:总结

本章节中,我们完成了 部分 的文章搜索功能。

  1. 使用 分包 创建了 search-blog 页面
  2. 分析页面得到了 三个组件
    1. 热搜列表:search-hot-list
    2. 搜索历史:search-history
    3. 搜索结果:search-result-list
  3. 定义了规则,控制了三个组件的展示规律
  4. 完成了 热搜列表 的功能
  5. 在完成 搜索历史 时,遇到了问题:search-blogsearch-historysearchData 和 组件 之间 强耦合

想要解决这个问题,那么我们需要用到一个新的东西,叫做 《全局状态管理工具》,那么这个东西怎么用呢?他有什么样的价值呢?

我们下一章再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/436368.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】深度剖析string类的底层结构及其模拟实现

文章目录 前言1. string的结构2. 构造、析构2.1 无参构造2.2 带参构造2.3 问题发现及修改c_stroperator []析构 2.4 合二为一 ——全缺省 3. 拷贝构造3.1 浅拷贝的默认拷贝构造3.2 深拷贝拷贝构造的实现 4. 赋值重载4.1 浅拷贝的默认赋值重载4.2 深拷贝赋值重载的实现 5. strin…

ES6 中的类(class)

前言 ES6 引入的 class 关键字具有定义类的能力。类是 ECMAScript 中新的基础性语法糖。虽然 ES6 表面上看起来可以支持正式的面向对象编程&#xff0c;但实际上它背后使用的依旧是原型和构造函数的概念。&#xff08;笔记内容参考《JavaScript 高级程序设计&#xff08;第 4 …

TTL反相器、OC门、TS门、推挽输出、开漏输出

TTL反相器 这是一个TTL反相器&#xff0c;这是经过了很多工程师多种设计最终沉淀出来的电路&#xff0c;这个电路是比较成熟的。我们只需要对这个电路进行解析即可&#xff0c;不需要再去研究当初是如何设计出来的。 学过CMOS应该知道&#xff0c;右侧的输出级其实也是个推挽输…

为什么程序实际可用内存会远超物理内存?

背景介绍 不知道在你刚接触计算机的时候&#xff0c;有没有这么一个疑问&#xff1a;“为什么我的机器上只有两个G 的物理内存&#xff0c;但我却可以使用比这大得多的内存&#xff0c;比如 256T&#xff1f;”反正我当时还是挺疑惑的&#xff0c;不过现在我可以来告诉你这个答…

如何将销售效果最大化:从人工智能聊天机器人到即时聊天

聊天机器人的崛起 从几年前开始&#xff0c;客户支持是聊天机器人使用的第一个爆发点。B2C引领潮流&#xff0c;B2B紧随其后。市场营销和销售最近也开始加入&#xff0c;让聊天机器人承担起迎接和引导网站游客的任务。现在&#xff0c;人工智能已经进入聊天&#xff0c;可以说…

机器学习 第一周

目录 1. 什么是机器学习(课本给出的部分定义) 我理解的机器学习:

Java基础:IO流有哪些,各有什么特点和功能

具体操作分成面向字节(Byte)和面向字符(Character)两种方式。 如下图所示&#xff1a; IO流的三种分类方式 IO流的层次结构 IO流的常用基类有&#xff1a; 字节流的抽象基类&#xff1a;InputStream和OutputStream&#xff1b; 字符流的抽象基类&#xff1a;Reader和Writer…

20、单元测试

文章目录 1、JUnit5 的变化2、JUnit5常用注解3、断言&#xff08;assertions&#xff09;1、简单断言2、数组断言3、组合断言4、异常断言5、超时断言6、快速失败 4、前置条件&#xff08;assumptions&#xff09;5、嵌套测试6、参数化测试7、迁移指南 【尚硅谷】SpringBoot2零基…

JAVA性能优化实例

目录 概述 Sql性能优化 多线程 利用内存缓存 功能优化 参考博客 概述 性能优化的几个点&#xff0c;大致可以分为&#xff1a; sql优化使用多线程利用内存&#xff0c;缓存等&#xff0c;将固定不常更改的数据放入在&#xff0c;存取更快的内存当中功能实现逻辑优化 Sql性…

五分钟,说说Python 中多线程共享全局变量的问题

嗨害大家好鸭&#xff01;我是爱摸鱼的芝士❤ 写在前面不得不看的一些P话&#xff1a; Python 中多个线程之间是可以共享全局变量的数据的。 但是&#xff0c;多线程共享全局变量是会出问题的。 假设两个线程 t1 和 t2 都要对全局变量g_num (默认是0)进行加1运算&#xff0c…

日常项目技术方案脉络

开篇引砖 软件在其生命周期中&#xff0c;当其进入稳定期后&#xff0c;大部分时间都处于迭代更新维护阶段。在这漫长的三年甚至五年的存活期内&#xff0c;我们需要面对林林种种大大小小的需求。今天我们就聊聊在这段期间&#xff0c;如何快速产出一份合格的技术方案。 方案给…

JavaScript经典教程(一)-- HTML基础部分

179&#xff1a;HTML基础部分&#xff08;元素分类、特性、特殊元素等&#xff09; 1、复习&#xff1a; HTML&#xff1a; 超文本标记语言 CSS&#xff1a; 层叠样式表 JavaScript&#xff1a; 脚本语言 http&#xff1a;超文本传输协议 https&#xff1a; 经过ssl加密的超…

如何搭建关键字驱动自动化测试框架?这绝对是全网天花板的教程

目录 1. 关键字驱动自动化测试介绍 2. 搭建关键字驱动自动化测试框架 步骤1&#xff1a;选择测试工具 步骤2&#xff1a;定义测试用例 步骤3&#xff1a;编写测试驱动引擎 步骤4&#xff1a;实现测试关键字库 步骤5&#xff1a;执行测试 3. 实现关键字驱动自动化测试的关…

c/c++:gets(),fgets(),puts(),fputs(),strlen(),字符串拼接函数

c/c&#xff1a;gets()&#xff0c;fgets()&#xff0c;puts()&#xff0c;fputs()&#xff0c;strlen()&#xff0c;字符串拼接函数 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的话&#xff0c; 我所知道的周…

C语言程序环境与预处理回顾总结

大概讲解与铺垫 首先&#xff0c;什么叫c语言的源代码&#xff1f;也就是我自己写的.c文件里面的代码&#xff0c;这个就叫做源代码。然后需要知道的是计算机他只认识二进制&#xff0c;因此他只能接收与执行二进制指令。也就是可执行的机器指令。然后我们必须得知道&#xff…

JavaWeb——tomcat(安装使用)

目录 WEB服务器-Tomcat 服务器概述 Web服务器 Tomcat Tomcat下载 安装与卸载 启动与关闭 WEB服务器-Tomcat 服务器概述 服务器硬件&#xff1a; 指的也是计算机&#xff0c;只不过服务器要比我们日常使用的计算机大很多。 服务器&#xff0c;也称伺服器。是提供计算服务…

【数据结构】第十一站:链式二叉树

目录 一、二叉树的创建 二、二叉树的遍历 1.前序中序后序遍历 2.层序遍历 三、二叉树的节点个数以及高度等 四、二叉树的构建和销毁 五、DFS和BFS 一、二叉树的创建 为了方便后面的讨论&#xff0c;我们在这里先手撕一颗二叉树 typedef int BTDateType; typedef struct …

Qt Designer

Qt Designer——即Qt设计师&#xff0c;是QT项目开发的可视化图形界面编辑器&#xff0c;通过设计师可以很方便地创建图像界面文件*.ui&#xff0c;然后将ui文件应用的源代码中&#xff0c;做到所见即所得&#xff0c;让界面的设计变得十分简单。下面介绍Qt Designer的简单使用…

使用PowerShell自动部署ASP.NetCore程序到IIS

asp.net core 安装asp.net core sdk https://dotnet.microsoft.com/en-us/download/dotnet/3.1 创建asp.net core项目 dotnet new webapi运行项目 访问https://localhost:5001/WeatherForecast iis配置 安装iis 以管理员身份运行powershell Enable-WindowsOptiona…

【计算机网络】学习笔记:第二章 物理层(五千字详细配图)【王道考研】

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…