Code前端首页关于Code前端联系我们

回顾Vue的单文件组件(SFC),你是否正在探索新的模式并一起比赛? (Vue2)

terry 2年前 (2023-09-08) 阅读数 162 #Vue

1。回顾Vue的单文件组件

1.1 一个文件的组成部分

单文件组件 Vue SFC(single-file-component)是指扩展名为 .vue 的文件。内容通常包含三个块
template(模板块) script(js脚本块) style(样式块)

回首Vue的单文件组件(SFC),探索新的模式,然后一起飙车?(Vue2)回首Vue的单文件组件(SFC),探索新的模式,然后一起飙车?(Vue2)

使用单文件组件开发.vue的优点:

  • 编写代码时更好的代码和语法提示
  • 更多模板语法(pug)\css预处理(更少)支持
  • 组件复用,比如我们可以将多个页面使用的相同功能提取出来,成为一个公共组件......

1.2 创建.vue文件的流程

插入重要知识点-loaderwebpack配置方法
官方文档:webpack.docschina.org/concepts/lo…

    配置方法
  • 1.webpack.config.js 这种方式webpack使用正则表达式来验证文件名
    loader从右到左(或从下到上)评估/执行
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: 'style-loader' },
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          },
        ]
      }
    ]
  }
};
内
 
  • 2。运行内联模式,不需要写css配置,直接加载即可,例如在js文件中加载style:
//app.js
import style0 from 'style-loader!css-loader!./my.unknow'
// 这样就指定了到my.unknow这个文件时以(从右到左)css-loader=>style-loader的顺序去解析
console.log('hey')
 
  • 2。另一种loader:投loader:

官方说法:loader总是被从右到左称为。在某些情况下,loader只关心请求后的元数据,而忽略前面的loader的结果。其实(从右到左)在执行loader之前,loader上的调试方法会叫从左到右民间:从左到右、从上到下的倾斜方法,作用:♼共享数据,将提前返回(跳过剩余的loader)
例如以下示例:

//loaderAwithPitch.js
module.exports = function (source) {
  console.log('runA')
  return `10000\n${source}`
};
// 到处pitch方法给webpack
module.exports.pitch = function (remainingRequest, precedingRequest, data) {
  console.log('pitch',remainingRequest,precedingRequest,data)
  return 'nothing';
  // return source;
}
 
//loaderB.js
module.exports = function (source) {
  console.log('runB')
  return `20000\n${source}\n`
};
 

然后直接在输入文件中配置loader

//index.js
import str from "./loaderAwithPitch!./loaderB.js!./todo.js";
console.log(str);
 

打包结果:只写了loader AwithPitch中pitch方法中的内容,不执行loader B和loader AwithPitch的默认导出函数

pitcvh未命名1621242580.pngpitcvh未命名1621242580.png
过程有点像 在 DOM 事件中捕获和冒泡 :

|- loaderAwithPitch `pitch`
  |- loaderB `pitch`
      |- requested module is picked up as a dependency
  |- loaderB normal execution
|- loaderAwithPitch normal execution
//流程是 loaderAwithPitch的pitch方法=>loaderB的pitch方法(如果有)=>loaderB执行=>loaderA执行
//期间如果pitch方法提前返回,将不执行后面的流程
 

.vue 文件最终是如何创建的?我们来看一个简单的 webpack 项目:

project未命名1621240317.pngproject未命名1621240317.png
输入文件是main.js,然后加载vue文件
我们都知道浏览器可以直接运行js代码,但是vue文件中的代码不能在浏览器中直接运行
这样 webpack 支持 vue 文件已经转换好了,配置如下

const { VueLoaderPlugin } = rquire("vue-loader");
module.exports = {
  mode: "development",
  module: {
    rules: [
      {
        test: /\.vue/,
        use: "vue-loader",
      },
      {
        test: /\.css$/,
        use: ["vue-style-loader", "css-loader"],
      },
    ],
  },
  plugins: [new VueLoaderPlugin()],
}
 

VueLoaderPlugin - 转换webpack配置的module.rule,伪代码:

vueplu未命名1621260327.pngvueplu未命名1621260327.png

vue-loader – 转换 .vue 文件:

vload未命名1621263770.pngvload未命名1621263770.png

  • VueLoaderPlugin对module.rule进行操作,在vue文件中添加block规则对应的pitchLoader和loader(从原来的rule规则复制而来)
  • vue-loader 使用 import 命令将 vue 文件转换为 js 代码 =>pitchLoader 将 import 命令转换为对应的 loader 块的导出命令 => loader的导出命令将 block 块的内容转换并返回处理后的结果

当其他文件导入这个vue文件执行var component = Normalizer()时,代码会在Normalizer中编译并添加新属性;返回的对象如下:

aaa未命名1621265799.pngaaa未命名1621265799.png

总结一下简单的模型:
.vue 文件 => vue-loader => js 文件
导入该文件里面的代码运行并返回 vue 组件配置对象

2。探索新模式

.vue 文件的优点不言而喻,现在我们来想一下缺点,对我来说是
有时候组件太多需要在IDE中维护时反复跳转?

现在让我们驱动

    :
    既然import是一个对象,那么让我们制作一个可以生成对象的对象,但同时我们可以做一些数据/方法❀计算配置,如Function| object|class,都可以实现,我们先尝试使用class同时编写对应的loader来分析我们定义的模板区的模板代码

class VueCar {
  constructor() {
    this.options = {
      data: {},
      methods: {},
      components: {},
      mounted:[]
    };
  }
  // 我们只要无脑的return this就能无限打点了
  components(obj) {
    Object.assign(this.options.components, ...obj);
    return this;
  }
  template() {
    // do
    return this;
  }
  style() {
    // do
    return this;
  }
  done() {
    return this;
  }
  data(obj) {
    Object.assign(this.options.data, ...obj);
    return this;
  }
  methods(fn) {
    Object.assign(this.options.methods, ...fn.call(this.options));
    return this;
  }
  mounted(fn){
    this.options.mounted.push(()=>fn(this.options))
    return this;
  }
  final(){//最后导出调用的方法,翻译this.options成VuecomponentOptions格式
    return transformToVue(this.options)
  }
}
 

然后这样写js文件

import List from './List.vue' //兼容vue文件
let Header = new VueCar()
  .template(() => <header>this is header</header>)
  .done()
  .style(
    <style>
      .message{
        color:blue;
      }
    </style>
  )
  .done()
  .mounted((options) => {
    console.log("mounted");
  });
let Content = new VueCar()
  .components({List})
  .template(() => <footer><List/>is footer</footer>)
  .mounted(() => console.log("footer mounted"));

let App = new VueCar();
App.components({
  Header,
  Content,
})
  .template(() => (
    <div>
      <div>{{ message }}</div>
      <button v-on:click="changeMessage">changeMessage</button>
    </div>
  ))
  .done()
  .data({
    message: "hey,vue",
  })
  .methods((options) => ({
    changeMessage() {
      options.data.message = Math.random();
    },
  }));

export { Header, Content, App };
 

这个js文件还必须配备vueCarLoader,解析并替换其中的模板/样式块(所以你需要。)
我们可以通过这种方式编写单独的几个组件js文件和导出是分开的。同时,也许我们的类也可以支持typescript配置……

ps:在测试过程中,我发现样式块无论如何都无法用js编写,并且IDE报错。也许未来需要插件支持?

sss未命名1621269157.pngsss未命名1621269157.png

根据上面的类模型,我构建了一个测试版本。名字是vue-highway。这是一个演示项目,大家看看
github.com/avenger9527…

image.pngimage.png
如图所示,
优点 – 在一个 js 中编写多个组件 / 兼容原来的写法
缺点 模板中不支持

报错错误),只能写v-on:click/不能写样式块(IDE)...

大佬们快来参与讨论吧!更多有趣的编码~ ?

多多批评!

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门