先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
正文
如果把这些配置全部写在后台库里面,根据当前选择的组件加载不同的配置,维护起来会相当麻烦,而且随着组件数量的增加,也会变得臃肿,所以我们可以将这些配置存储在服务端,后台只需要根据存储的规则进行解析便可,举个例子,我们其实可以存储这样的编辑配置:
[
{
“blockName”: “按钮布局设置”,
“settings”: {
“src”: {
“type”: “input”,
“require”: true,
“label”: “按钮文案”
}
}
}
]
我们在编辑后台,通过接口请求到这些配置,便可以进行规则渲染:
/**
* 根据类型,选择创建对应的组件
* @param {VNode} vm
* @returns {any}
*/
createEditorElement (vm: VNode) {
let dom = null
switch (vm.config.type) {
case ‘align’:
dom = this.createAlignElement(vm)
break;
case ‘select’:
dom = this.createSelectElement(vm)
break;
case ‘actions’:
dom = this.createActionElement(vm)
break;
case ‘vue-editor’:
dom = this.createVueEditor(vm)
break;
default:
dom = this.createBasicElement(vm)
}
return dom
}
组件选择区
首先我们需要考虑的是,组件怎么进行注册?因为组件被用户选用的时候,我们是需要渲染该组件的,所以我们可以提供一段 node 脚本来遍历所需组件,进行组件的安装注册:
// 定义渲染模板和路径
var OUTPUT_PATH = path.join(__dirname, ‘…/packages/index.js’);
console.log(chalk.yellow(‘正在生成包引用文件…’))
var INSTALL_COMPONENT_TEMPLATE = ’ {{name}}';
var IMPORT_TEMPLATE = ‘import {{componentName}} from ‘{{name}}’’;
var MAIN_TEMPLATE = `/* Automatic generated by ‘./compiler/build-entry.js’ */
{{include}}
const components = [
{{install}}
]
const install = function(Vue) {
components.map((component) => {
Vue.component(component.name, component)
})
}
/* istanbul ignore if */
if (typeof window !== ‘undefined’ && window.Vue) {
install(window.Vue)
}
export {
install,
{{list}}
}
`;
// 渲染引用文件
var template = render(MAIN_TEMPLATE, {
include: includeComponentTemplate.join(endOfLine),
install: installTemplate.join(,${endOfLine}
),
version: process.env.VERSION || require(‘…/package.json’).version,
list: listTemplate.join(,${endOfLine}
)
});
// 写入引用
fs.writeFileSync(OUTPUT_PATH, template);
最后渲染出来的文件大概是这样:
import WButton from ‘w-button’
const components = [
WButton
]
const install = function(Vue) {
components.map((component) => {
Vue.component(component.name, component)
})
}
/* istanbul ignore if */
if (typeof window !== ‘undefined’ && window.Vue) {
install(window.Vue)
}
export {
install,
WButton
}
这个也是组件库的通用写法,所以这里的思想就是把发布到 npm
上的组件,进行聚合,聚合成一个组件包引用,我们在后台编辑的时候,是需要全量引入的:
import * as W_UI from ‘…/…/packages’
Vue.use(W_UI)
这样,我们组件便注册完了,组件选择区,主要是提供组件的可选项,我们可以遍历组件,提供一个个 List 让用户选择,当然如果我们每个组件如果只提供一个组件名,用户可能并不知道组件长什么样,所以我们最好可以提供一下组件长什么样的缩略图。这里我们可以在组件发布的时候,也通过 node
脚本进行。这里要实现的代码比较多,我就大致说一下过程,因为也不是核心逻辑,可有可无,只能说有了体验上会好一点:
-
用户启用 dev-server 进行代码编写测试
-
server 脚本使用 Chrome 工具 puppeteer,调整页面到手机端模式, 进行当前 dev-server 截图。
-
生成截图文件,上传到node服务,关联组件
这样,就可以在加载组件选择区的时候,为组件附上缩略图。
组件预览区
当用户在选择区选择了组件,我们需要展示在预览区域,那么我们怎么知道用户选择了哪些组件呢?总不能提前全部把组件写入渲染区域,通过v-if
来判断选择吧?当然没有这么蠢,Vue 已经提供了动态组件的功能了:
:class=“[index===currentEditor ? ‘active’ : ‘’]”
:is=“select.name”
:data=“select.data”>
为什么我们不用缩略图代替真实组件?一方面生成的缩略图尺寸存在问题,另一方面,我们需要编辑的联动性,就是编辑区的编辑需要及时的反馈给用户。
额外的问题
说了这么多,貌似一切都很顺利,但是这样在实践的时候,发现了存在一个明显的问题就是:我们中间的预览区域其实就是为了尽可能模拟移动端页面效果。但是如果我们加入了一些包含类似 position: fixed
样式的组件,会发现样式上就出现了明显的问题。典型的比如Dialog Loading
等。所以我们参考了 m-ui组件库的设计,将中间预览操作容器展示为一个iframe
。将iframe大小调整为375 * 667
,模拟 iPhone 6
的手机端。这样就不会存在样式问题了。可是这样又出现了另一个难点,那就是左侧的编辑数据如何及时的反应到iframe
中?没错,就是postMessgae
,大致思路如下:
利用 vuex
做数据存储池,所有的变化,通过 postMessgae
进行同步,这样我们只用确保数据池中的数据变化,便可以映射到渲染层的变化。比如,我们在预览区进行了组件选择和拖拽排序,那么我们只需通过 vuex
出发同步信息便可:
// action.ts
const action = {
setCurrentPage ({commit, state}, page: number) {
// 更新当前store
commit(‘setCurrentPage’,page)
// 对应postMessage
helper.postMsgToChild({type: ‘syncState’, value: state})
},
// …
}
Template 模板的实现
模板的设计实现,我参考了 Vue-cli 2.x
版本的思想,把这里的模板,存在了对应的 git
仓库中。当用户需要进行页面构建的时候,直接从 git 仓库中拉取对应的模板即可。当然拉取完,也会缓存一份在本地,以后渲染,直接从本地缓存中读取即可。我们现在把中心放在模板的格式和规范上。模板我们采用什么样的语法无所谓,这里我才用了和 Vue-cli
一样的Handlerbars
引擎。这里直接上我们模板的设计:
backgroundColor: ‘{{bgColor}}’,
backgroundImage: ‘{{bgImage}}’ ? ‘url({{bgImage}})’ : null,
backgroundSize: ‘{{bgSize}}’,
backgroundRepeat: ‘no-repeat’
}">
{{#components}}
<{{name}} class=“temp-component” :data=“{{tostring data}}” data-type=“{{upcasefirst name}}”></{{name}}>
{{/components}}