开发一个在线检测文章中代码块占比的页面( 下 )

528 阅读3分钟

在前两篇文章中,我们已经完成了大部分的工作,接下来,我们将编写页面样式以及交互部分。把这个项目完善好。

系列

在线使用地址qc2168.github.io/article-inf…

页面布局

输入卡片样式

4.gif

body标签中设置flex布局,让元素能够居中。并将背景颜色设置为灰色,并在里边给一个容器组件,使用mx-auto功能类,

<body class="bg-gray-300 flex justify-center items-center">
    <div id="container" class="container mx-auto flex flex-nowrap">
    </div>
</body>

body标签中创建一个卡片,这里使用了较多的tailwind的样式类,如果你是第一次接触这类框架,你可能会觉得比较复杂。可查阅tailwind文档

<div id="article" class="flex-grow h-auto rounded-lg shadow-sm bg-white overflow-hidden p-10 mr-2 relative">
  <img src="./gitHub.png" class="top-4 right-4 absolute w-8 h-8" alt=""/>
  <p class="font-mono text-3xl font-bold tracking-wider leading-tight text-center mb-5 uppercase">
    article
  </p>
  <div contenteditable="plaintext-only" placeholder="Write something ..." id="inp-content"
       class="max-h-full break-all text-justify bg-gray-50 border-2 hover:bg-gray-100 border-gray-200 ease-out block transition-all duration-700 h-20 max-h-96 py-3 px-4 overflow-hidden font-mono cursor-auto rounded-xl"
       style="outline:none;"></div>
</div>

index.scss中将htmlbody标签的宽高设置为100%,让卡片可以居中在中间。你也可以在htmlbody标签中加入w-fullh-full类改变元素的宽高。

html,body{
  width: 100%;
  height: 100%;
}

模拟inpit中的placeholder,当inp-content的输入框为空时,显示定义的placeholder的值。

#inp-content[placeholder]:empty:before {
  content: attr(placeholder);
  color: #555;
}

6.gif

inp-content获取焦点时,将inp-content及它的父元素高度撑开到一定范围。

focus:h-96 focus:border-indigo-400

在项目根目录下的tailwind.config.js中添加以下代码。为height属性开启focus变体。

variants: {
  extend: {
    height: ['focus'],
  },
},

7.gif

文章分析卡片

即是右边的result卡片,用于显示文章的字数分析。

8.png

它与左边的article卡片效果一样,只不过是里边的内容不一样。

  <div id="resultBox"
       class="overflow-hidden w-2/6 flex-none rounded-lg transition-all duration-700 shadow-sm py-10 bg-white flex flex-col items-center">
    <p class="font-mono text-3xl font-bold tracking-wider leading-tight text-center mb-5 uppercase">
      result
    </p>
  </div>

9.png

w-2/6移除掉,替换成w-0,意思是将宽度设置为0,后续我们会通过typescript动态的控制这个卡片的宽度。

右边的饼状图是使用ECharts绘制的(相关文档),我们先安装ECharts这个库。

ECharts

安装ECharts

在终端执行以下命令,安装ECharts

yarn add echarts 
封装ECharts

pages/index中创建一个RChart.ts文件,用来封装这个饼状图。

引入并注册饼图所需的组件。

import {
  TooltipComponent,
  LegendComponent,
} from 'echarts/components';
import {
  PieChart, PieSeriesOption,
} from 'echarts/charts';
import {
  CanvasRenderer,
} from 'echarts/renderers';

use(
  [TooltipComponent, LegendComponent, PieChart, CanvasRenderer],
);

编写一个RChart类,它需要传入一个DOM元素,用于绘制饼图。

export class RChart {
	private chartInstance : echarts.ECharts;
	
	constructor(dom:HTMLElement) {
 	 this.chartInstance = echarts.init(dom);
	}
}

添加renderChart方法,用于渲染图标,需要传入文章对应的数据进行饼图渲染。是个数组类型的参数。

export type dataType = {
  value: number, name: string
}
type ECOption = echarts.ComposeOption<PieSeriesOption>;
export class RChart {
    // ... 忽略一些代码
	public renderChart=(data:dataType[]):void => {
    const option: ECOption = {
      tooltip: {
        trigger: 'item',
      },
      legend: {
        top: '5%',
        left: 'center',
      },
      series: [
        {
          name: '占比',
          type: 'pie',
          radius: ['40%', '70%'],
          avoidLabelOverlap: false,
          itemStyle: {
            borderRadius: 12,
            borderColor: '#fff',
            borderWidth: 2,
          },
          label: {
            show: false,
            position: 'center',
            formatter: '{d}%',
          },
          emphasis: {
            scale: true,
            scaleSize: 5,
            label: {
              show: true,
              fontSize: '18',
              fontWeight: 'bold',
            },
          },
          labelLine: {
            show: false,
          },
          data,
        },
      ],
    };
    this.chartInstance.setOption(option);
  }
}

resultBox元素中创建一个饼图的渲染区域,并通过内联样式指定宽高。

<div id="resultChart" class="hidden" style="width: 20rem;height: 25rem;"></div>

jQuery

安装jQuery

在终端执行以下命令,安装jquery

yarn add jQuery @types/jquery

配置webpack.config.ts文件,使用ProvidePlugin$暴露出来,这样子在项目中就可以直接使用$进行使用了。

import { ProvidePlugin } from 'webpack';
plugins: [
  new ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
  }),
],

在index.ts中引入我们之前写好的CheckArticle以及RChart类。

import CheckArticle from './CheckArticle';
import {
  dataType, RChart,
} from './RChart';

动态交互

思路 / 步骤
  • 实例化CheckArticleRChart类,RChart类需要传入渲染的DOM元素
  • 监听输入框键盘事件
    • 获取输入框元素,通过CheckArticle类中暴露的changeContent方法更改类中文章的内容。
    • 调用类中的matchShortCodematchLongCode方法获取代码和代码块的长度。将这两个数据转换成饼图需要的对象格式。
    • 调用RChart类中的renderChart方法进行饼图的渲染
    • 判断当前输入框元素是否有元素
      • 当前有内容:显示文章分析卡片
      • 当前无内容:隐藏文章分析卡片
$(($) => {
  // 获取输入框元素
  const inpContent = $('#inp-content');
  const CA = new CheckArticle('');
  const RC = new RChart(document.getElementById('resultChart')!);
  inpContent.on('keyup', () => {
    // 获取输入框内容
    const content: string = inpContent.html();
    CA.changeContent(content);
	// 生成数据
    const data: dataType[] = [
      {
        value: CA.matchShortCode(),
        name: '代码长度',
      },
      {
        value: CA.matchLongCode(),
        name: '代码块长度',
      },
      {
        value: CA.articleCount - CA.matchLongCode() - CA.matchShortCode(),
        name: '文本',
      }];
    // 判断当前输入框内容
    // 是否显示分析结果卡片
    if (content) {
      RC.renderChart(data);
      // 添加result
      $('#resultBox')
        .removeClass('w-0')
        .addClass('w-2/6');
      $('#resultChart')
        .removeClass('hidden');
      $('#inp-content')
        .addClass('h-96');
    } else {
      $('#inp-content')
        .removeClass('h-96');
      $('#resultChart')
        .addClass('hidden');
      $('#resultBox')
        .removeClass('w-2/6')
        .addClass('w-0');
    }
  });
});

到了这里,我们这个页面已经开发完毕啦!

1.gif