基于Strview.js项目脚手架StrviewApp是怎么搭建起来的?

简介: 基于Strview.js项目脚手架StrviewApp是怎么搭建起来的?

前言


前几天,因为借着看源码的热乎劲,搞了一个玩具Js库Strview.js。为什么会搞这么一个玩具库呢?其实也不全是因为晚上闲的没事,主要还是想通过实操来锻炼自己的开发能力。之前,我也写过一篇文章,那篇文章只是大体介绍了一下,没有深究。之前大家可能觉得它跟Vue.js差不多,是的,正是借鉴Vue.js的思想,但是有些地方还是不一样(个人觉得)。所以,今天,这篇文章介绍基于Strview.js搭建的项目脚手架工具

StrviewApp。如果你觉得对自己有用,可以继续看下去。如果觉得这篇肯定是篇垃圾文章,你也可以避而远之。好了,我们现在就进去正题。准备好了吗?一起跟我来吧!


快速上手StrviewAPP


你可以通过StrviewCLI快速初始化StrviewAPP项目,你可以这样:


  1. 全局安装。


npm i strview-cli -g


  1. 安装完成之后,你可以查看版本。


strview-cli -v


  1. 最后,就是初始化项目了,<projectName>是自定义项目名称。


strview-cli init <projectName>


or


strview-cli i <projectName>


这样,一个StrviewAPP项目就这么搭建完成了。


StrviewAPP项目结构


下图就是StrviewAPP项目组织结构。


微信截图_20220506193448.png


下面,我将介绍每个文件及文件夹的作用。


  • config


这个是webpack配置文件夹,关于webpack的配置都在这配置。文件夹中里面有如下三个文件,分别如下:


- webpack.base.js  // 基础配置
- webpack.dev.js  // 开发环境配置
- webpack.pro.js  // 生产环境配置


  • public


资源文件夹。


- favicon.ico  // 网站标识
- index.html  // 模板文件


  • .gitignore


哪些文件不需要添加到版本管理中。


  • .prettierrc


Prettier 规则配置文件。


  • package.json


定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。


  • src


这个文件夹是StrviewAPP项目的主要文件夹,下面我们来看下这个文件夹里面到底有什么。


- assets //存放静态文件
- components // 组件文件夹
- data // 公用状态文件夹
- methods // 方法文件夹
- style // 样式文件夹
- template // 模板文件夹
- App.js // 页面入口
- main.js // 项目入口文件


Src文件夹详析


上面我们分析完了项目结构,那么下面我们将进一步分析Src文件夹中的文件构成以及它们之间如何配合的。


1. main.js


首先,我们看下main.js文件,这是项目入口文件,我们来看下文件中的内容。


import { createView } from 'strview';
import data from './data';
import App from './App';
import methods from './methods';
createView({
  el: "#app",
  template: App,
  data
});
// The event is handled after the createview API
methods();


我们先引入了strview.js,导入createView这个API用于创建视图。那么,我们我们跳到下面看下这个API是怎么使用的。首先我们传入一个对象字面量,第一个属性是el属性,它是挂载的DOM节点。第二个属性是template属性,它是用于显示视图的模板。第三个属性是data属性,传入值为显示的数据。最后,我们看到有这么一行注释The event is handled after the createview API,意思是事件方法必须要在createViewAPI之后调用,即这里的methods();


2. App.js


上面说到,App.js用与显示视图的模板,那么下面我们来看下。


import myParagraph from './components/myParagraph';
import card from './components/card';
import helloTemplate from './template/helloTemplate';
import './style/index.css';
const App = `
${helloTemplate}
<div class="content">
    <button class="color-red">点击</button>
    <p class="txt">{a},{b},(a和b都改变)</p>
    <ul class="list">
      <li>{age}</li>
      <li>{name}</li>
      <li>{msg}</li>
    </ul>
    <p class="txt">{a},(a会改变)</p>
    <p class="txt">{b},(b会改变)</p>
    <input value="{msg}"></input>
    <p>{obj.a.b}</p>
    <p>{arr}</p>
    <p>{ob.name}</p>
</div>
${myParagraph}
${card}<my-card><span slot="my-card-txt">{b}</span></my-card>
`
export default App


我们看到在代码的末尾导出了一个模板字符串,也就是常量App。我们可以看到模板字符串中都是些类似标签语句的代码。是的,这也是Strview.js的关键之处,使用含有类似标签语句的模板字符串来构建视图。


另外,我们看到顶部除了引入样式文件,还从components文件夹引入了两个文件,template文件夹中引入了一个文件。我们从前面目录结构知道,components文件夹存放的是组件,而template文件夹存放的是模板文件。如何将导入模板与组件呈现到页面上呢?那么就需要在模板字符串中使用${}占位符。在这里你可能会感到很困惑,因为没有看到这些文件中什么内容,不过不要着急,我们慢慢来。你在这里只需要记住它们在这里占位就可以了。


你可能会看到<my-card></my-card>这种标签,你可能说没见过!这只是一个自定义组件。具体为什么这样写,我们下面到组件时再分析。但是需要说明的是,如果我们组件中需要存放内容时,我们需要在自定义组件前使用一个占位符${},如这里的${card}card是引入的组件。


最后,我们在标签中都会发现类似这种{}符号,它是用来挂载数据的,也就是为了动态更新数据的。数据这块我们后面再细讲。


3. template


上面说到,这个文件夹是存放模板文件的,我们就一探究竟。


- helloTemplate.css
- helloTemplate.js


helloTemplate.css样式文件没有什么好说的。


.container {
  text-align: center;
  margin-top: 100px;
  line-height: 46px;
}
.container > img {
  margin-bottom: 40px;
}


helloTemplate.js我们来看下这个js文件。


import logo from '../assets/logo.png';
import './helloTemplate.css';
export default `
<div class="container">
  <img src="${logo}"/>
  <h1>Hello Strview.js</h1>
</div>
`;


在上面代码中可以看到我们头部引入了一个图片还有一个样式文件,下面接着导出了一个模板字符串。 引入的图片呢!使用${}占位符来绑定到img标签上。


简单介绍下template文件夹之后,我们下面看下components文件夹。


4. components


这个文件夹的是存放组件的,组件这个概念大家可能非常熟悉,在目前Vue、React这些前端框架中都有相应的应用。


我们先来看下这个文件夹的目录结构。


- card.js
- myParagraph.js


可以看到,有两个js文件。


先看myParagraph.js这个文件。


customElements.define('my-paragraph',
    class extends HTMLElement {
        constructor() {
            super();
            const template = document.getElementById('my-paragraph');
            const templateContent = template.content;
            this.attachShadow({ mode: 'open' }).appendChild(
                templateContent.cloneNode(true)
            );
        }
    }
);
const myParagraph = `<template id="my-paragraph">
<style>
    p {
        color: white;
        background-color: #666;
        padding: 5px;
    }
</style>
<p>
    <slot name="my-text">My default text</slot>
</p>
</template>
<my-paragraph>
<span slot="my-text">Let's have some different text!</span>
</my-paragraph>
<my-paragraph>
<ul slot="my-text">
    <li>Let's have some different text!</li>
    <li>In a list!</li>
</ul>
</my-paragraph>`
export default myParagraph


我们先看上一部分,customElements对象下有一个define方法。这是什么方法呢?


其实这部分利用了Web Components。它是什么呢?我们在MDN这样定义它的。


Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的web应用中使用它们。


Web Components拆开来讲其实也挺复杂,我们在这里就不详细分析了。以下是MDN网址,大家可以跟着做几个例子。


https://developer.mozilla.org/zh-CN/docs/Web/Web_Components


我们在这里是需要知道define方法第一个参数需要传一个自定义标签名,第二个参数是传入一个类。需要自定义的地方是第一个参数与第二个参数中getElementById()方法中的参数,推荐使用相同的字符串。


调用define方法完成后,你需要在下面模板字符串中首先要使用template标签包裹起来,你可以理解成初始化。我们可以看到在template标签上有一个id选择器与上面的getElementById()方法中的参数一样。是的,这地方必须一一对应。另外,我们看到紧接着下面有一个style标签,这是定义组件样式的。最后就是组件的内容了。这里定义了一个p标签,里面是一个插槽,定义了一个name属性。并且这里有一个标签文本,这个文本内容是默认显示的,如果组件中没有内容,则这个内容就会默认显示。


<template id="my-paragraph">
<style>
    p {
        color: white;
        background-color: #666;
        padding: 5px;
    }
</style>
<p>
    <slot name="my-text">My default text</slot>
</p>
</template>


我们接着看下面代码,它们都是用<my-paragraph></my-paragraph>包裹起来。另外,标签里面则是普通的标签语句。但是,有一点不一样的是,这些普通的标签语句都有一个slot属性,这个属性用于当作插槽的模板。


<my-paragraph>
<span slot="my-text">Let's have some different text!</span>
</my-paragraph>
<my-paragraph>
<ul slot="my-text">
    <li>Let's have some different text!</li>
    <li>In a list!</li>
</ul>
</my-paragraph>


分析完了myParagraph.js文件,我们接着分析card.js文件。


其实与myParagraph.js文件一样,只不过它是负责定义组件。在上面的App.js中,我们提到我们需要在自定义组件前使用一个占位符${},如这里的${card}card是引入的组件,就是指的它。


customElements.define('my-card',
    class extends HTMLElement {
        constructor() {
            super();
            const template = document.getElementById('my-card');
            const templateContent = template.content;
            this.attachShadow({ mode: 'open' }).appendChild(
                templateContent.cloneNode(true)
            );
        }
    }
);
const card = `<template id="my-card">
<style>
    div {
        color: #333;
        background-color: #f4f4f4;
        padding: 5px;
    }
</style>
<div>
    <slot name="my-card-txt"></slot>
</div>
</template>
`
export default card


5. data


这个文件夹是负责存放数据状态的文件,里面主要有这两个文件。


- index.js
- ob.js


我们先来看下index.js文件,非常简单,就是单纯的导出一个对象,另外ob.js文件也是。


index.js


import ob from './ob';
export default {
    a: "Hello",
    b: 18,
    name: "maomin",
    age: 9,
    msg: 'Strview',
    arr: ['0'],
    obj: {
        a: {
            b: 1
        }
    },
    ob
}


ob.js


export default {
    name: 'kk'
}


6. methods


我们在main.js文件中中提到一点。


import methods from './methods';
// The event is handled after the createview API
methods();


就是调用这个方法。那么,我们下面看下这个methods文件夹,我们知道这个文件夹的作用是提供事件处理方法的。它的目录结构如下:


- index.js
- item.js


先来看下item.js这个文件。


import { reactive, ref } from 'strview'
function executes() {
    reactive().obj.a.b = 3;
    ref().name = 'Strview.js';
}
function useItem() {
    ref().b = 100;
}
export {
    executes,
    useItem
}


我们可以看到在头部引入了两个方法,reactiveref这两个方法前者负责处理复杂类型的数据,如数组、嵌套对象,后者处理简单类型的数据,如单一对象、原始值。可以看到在上面代码我们通过调用reactive()ref()这两个方法来实现数据的响应式,然后导出这两个executes()useItem()方法。


接着,我们来看下index.js文件。


import { eventListener } from 'strview';
import { executes, useItem } from './item';
const eventList = [
    ['.color-red', 'click', executes],
    ['.list>li:nth-child(2)', 'click', useItem]
]
function methods() {
    for (let index = 0; index < eventList.length; index++) {
        const element = eventList[index];
        eventListener(...element);
    }
}
export default methods


我们首先在文件顶部引入了一个eventListener方法,然后接着从item文件夹引入的之前导出的两个方法。通过定义一个数组,来不断地循环调用eventListener方法。


最后导出methods方法。


7. style


这个是存放样式的文件,不过多介绍了。


index.css


* {
  margin: 0;
  padding: 0;
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
.content {
  text-align: center;
  margin-top: 50px;
}


8. assets


这个文件夹存放的是静态资源,比如图片之类的资源。


项目启动


  1. 初始化安装依赖


yarn install


OR


npm install


  1. 启动项目


yarn start


OR


npm run start


  1. 打包部署


yarn build


OR


npm run build


项目一览


微信截图_20220506193510.png


结语


谢谢你的阅读!


这个脚手架相比于现在热门的前端框架中的脚手架肯定是没有可比性,可以当做是玩具吧!也可以当做自己看源码之后自己的一些感悟吧!



相关文章
|
1月前
|
开发框架 JavaScript 安全
js开发:请解释什么是Express框架,以及它在项目中的作用。
Express是Node.js的Web开发框架,简化路由管理,支持HTTP请求处理。它采用中间件系统增强功能,如日志和错误处理,集成多种模板引擎(EJS、Jade、Pug)用于HTML渲染,并提供安全中间件提升应用安全性。其可扩展性允许选用合适插件扩展功能,加速开发进程。
|
1月前
|
JSON JavaScript 前端开发
解决js中Long类型数据在请求与响应过程精度丢失问题(springboot项目中)
解决js中Long类型数据在请求与响应过程精度丢失问题(springboot项目中)
42 0
|
1月前
|
JavaScript
vue.js项目评估流程图特效
vue.js项目评估流程图特效
86 2
vue.js项目评估流程图特效
|
2月前
VUE.初始化项目报错缺少core-js
VUE.初始化项目报错缺少core-js
36 0
|
3月前
|
分布式计算 JavaScript
JS项目小Tipes总结
JS项目小Tipes总结
|
3月前
|
存储 JavaScript 前端开发
JS项目练习
JS项目练习
|
3月前
|
JavaScript 前端开发 Java
面试官:你的项目有什么亮点?我:解决了JS脚本加载失败的问题!
面试官:你的项目有什么亮点?我:解决了JS脚本加载失败的问题!
|
2天前
|
缓存 JavaScript 前端开发
js开发:请解释什么是Webpack,以及它在项目中的作用。
Webpack是开源的JavaScript模块打包器,用于前端项目构建,整合并优化JavaScript、CSS、图片等资源。它实现模块打包、代码分割以提升加载速度,同时进行资源优化和缓存。Webpack的插件机制可扩展功能,支持热更新以加速开发流程。
13 2
|
9天前
|
JavaScript
node.js输入项目目录结构并展示
node.js输入项目目录结构并展示
5 0
|
1月前
|
JavaScript 前端开发 编译器
js开发: 请解释什么是Babel,以及它在项目中的作用。
**Babel是JavaScript编译器,将ES6+代码转为向后兼容版本,确保在旧环境运行。它在前端构建中不可或缺,提供语法转换、插件机制、灵活配置及丰富的生态系统,支持代码兼容性和自定义编译任务。**
18 6