建立无需build的vue单页面应用SPA框架

news2024/12/23 1:08:28

vue、react这种前端渲染的框架,比较适合做SPA(Single Page Application)。如果用ejs做SPA,js代码控制好全局变量冲突不算严重,但dom元素用jquery操作会遇到很多的名称上的冲突(tag、id、name)。

SPA要解决的问题:

(1)业务组件用什么文件格式?如果使用*.vue文件,需要在部署前build转换。使用*.js文件,部署前不需要buid转换。本来js的初心就是“即改即用”,我不太喜欢ts,jsx这些需要build的东西。

(2)业务组件如何加载?业务组件不可能写的时候全部知道(根据用户权限决定),也不可能一次性全部加载(影响首屏效率),应该是需要的时候,才从服务器加载。vue为此提供了异步组件,可以用Vue.defineAsyncComponent来创建。

demo.html

<html>
  <header>
  </header>
  <head>
    <!-- <script src="/js/jquery-1.11.1/jquery-1.11.1.min.js"></script> -->
    <!-- <script src="/js/vue-3.3.4/dist/vue.global.js"></script> -->
    <script type="importmap">
      {
        "imports": {
          "vue": "/js/vue-3.3.4/dist/vue.esm-browser.js",
          "easyui":"/js/v3-easyui-3.0.14/dist/v3-easyui.js"
        }
      }
    </script>
    <style>
      @import '/js/v3-easyui-3.0.14/dist/themes/default/easyui.css';
      @import '/js/v3-easyui-3.0.14/dist/themes/icon.css';
      @import '/js/v3-easyui-3.0.14/dist/themes/color.css';
      @import '/js/v3-easyui-3.0.14/dist/themes/vue.css';
    </style>
  </head>
  <body>
    <div id="app"></div>

    <script type="module">
      import * as Vue from 'vue';
      //console.log(Vue);
      import EasyUI from 'easyui';
      //console.log(EasyUI);
      import main from './com.main.js';
      
      let app=Vue.createApp(main);
      app.use(EasyUI);
      app.config.globalProperties.t=function(DDKey){return DDKey};
      //console.log(app);
      app.mount('#app');
    </script>
  </body>
</html>

页面划分为上中下三层,中间划分为左右两部分,左边是功能树,右边是功能区。

com.main.js

import * as Vue from 'vue';
import EasyUI from 'easyui';
//console.log(EasyUI);
import Com_Header from './com.header.js';
import Com_Left from './com.left.js';

export default {
    components: {
        Com_Header,Com_Left
    },
    data() {
      return { 
        tabFile:null,
        tabs:[]
      }
    },
    created(){
        this.$messager.ok=this.t('OK');
        this.$messager.cancel=this.t('Cancel');
    },
    methods:{
        switchTab(name,file){
            console.log(name,file);
            console.log(this.$refs.tabs);
            let tab=null;
            for(let i=0;i<this.tabs.length;i++){
                if (this.tabs[i].name==name){
                    tab=this.tabs[i];
                    this.$refs.tabs.select(i);
                    break;
                }
            }
            if (!tab){
                let component=Vue.defineAsyncComponent(function(){
                    let com=import(file);
                    let comMark=Vue.markRaw(com);
                    return comMark;
                });
                component=Vue.shallowRef(component);
                this.tabs.push({name,component});
                this.$nextTick(function(){
                    this.$refs.tabs.select(this.tabs.length-1);
                });
            }
        },
        onCloseTab(tab){
            console.log(tab);
            console.log(tab.title);
            for(let i=0;i<this.tabs.length;i++){
                if (this.tabs[i].name==tab.title){
                    this.tabs.splice(i,1);
                    break;
                }
            }
        }
    },
    template: `
        <a href="/">{{t('Home')}}</a>
        <h1>{{t('Demo:translate at frontend browser,translate needed(vue)')}}</h1>
        <span>SPA:Single Page Application</span>
        <div className='layout-header2' style="background-color:bisque">
            <Com_Header></Com_Header>
        </div>
        <div className='layout-middle'>
            <div v-Resizable="{minWidth:200,handles:'e'}" className='layout-left' style="width:200px;float:left;overflow:hidden;background-color:aquamarine">
                <Com_Left :switchTab=switchTab></Com_Left>
            </div>
            <div className='layout-right' style="margin-left:200px;overflow:hidden">
                <Tabs ref=tabs :scrollable="true" :plain=true @tabClose=onCloseTab>
                    <TabPanel v-for="tab in tabs" :key="tab.name" :title="tab.name" :closable=true>
                        <component :is="tab.component">
                        </component>
                    </TabPanel>
                </Tabs>
            </div>
            <div style="clear:both"></div>
        </div>
        <div className='layout-footer' style="background-color:brown;text-align:center">
            <span>copyright© Acroprise Inc. 2001-2023</span>
        </div>
    `
}

这里要注意Vue.markRaw和Vue.shallowRef两个函数,如果不写,会有警告:

[Vue warn]: Vue received a Component which was made a reactive object. This can lead to unnecessary performance overhead, and should be avoided by marking the component with `markRaw` or using `shallowRef` instead of `ref`.

com.left.js

let Com_Left={
  props:['switchTab'],
  data(){
    return{   
    }
  },
  methods:{
    menu_click(e){
      //console.log(e);
      let name=e.target.innerHTML;
      //console.log(name);
      let file=e.target.getAttribute('file');
      //console.log(file);
      this.switchTab(name,file);
      e.preventDefault();
    }
  },
  template:`
    <div>
      <a href='/'>{{t('Home')}}</a><br/>
      <a href='DDEditor' @click=menu_click file='/vue/app/DDEditor/page.DDEditor.js'>{{t('Data Dictionary Editor')}}</a><br/>
      <a href='likeButton' @click=menu_click file='/vue/app/likeButton/page.likeButton.js'>{{t('Like Button')}}</a><br/>
      <a href='About' onClick={{this.menu_click}} file=''>{{t('&About')}}</a>
    </div>
  `
}
export default Com_Left;

效果如下:

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

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

相关文章

运动蓝牙耳机怎么选、好用的运动蓝牙耳机推荐

在快节奏的现代生活中&#xff0c;运动成为了释放压力、保持健康和放松身心的重要方式。跑步、健身、骑行等各类运动成为了人们日常生活中不可或缺的一部分。然而&#xff0c;一场精彩的运动体验离不开动感的音乐伴奏。为了满足人们对高品质音乐的追求&#xff0c;一款出色的运…

nvm安装、管理多个node版本

1、官网下载nvm https://github.com/coreybutler/nvm-windows/releases 2、解压ZIP&#xff0c;双击nvm-setup.exe(假如以前安装了node.js&#xff0c;把以前的卸载了再安装nvm) 3、安装nvm 注意&#xff1a;这一步的nodejs目录需要手动创建 4、安装完毕&#xff0c;设置下载镜…

OpenCV动态人物识别代码

动态人物识别代码 int main() {// 打开视频文件或摄像头VideoCapture cap("vtest.avi");// VideoCapture cap(0); // 使用默认摄像头if (!cap.isOpened()){std::cout << "无法打开视频文件或摄像头流" << std::endl;return -1;}// 读取第一帧…

幽灵依赖是什么,pnpm出现的意义,使用pnpm创建一个vue3项目

什么是幽灵依赖&#xff08;幻影依赖&#xff09; 比如我们创建一个全新的vue3项目 然后我们正常地通过npm install来下载依赖 然后我们发现&#xff0c;node_ modules文件夹下的很多依赖&#xff0c;我们在package.json中明明没去声明却都下载下来了 那么这些没声明却下载…

SQL-游标-查询

/***DB版本&#xff1a;SQL Server 2022***/ --切换数据库 use MyDatabase--创建游标(scroll&#xff1a;滚动游标) declare mycur cursor scroll for select EmpNo from Employee--打开游标 open mycur --提取第一行 fetch first from mycur --提取最后一行 fetch last from m…

ansible自动化安装及简单操作

目录 一、运行机制 二、安装 1.下载ansible 2.配置免密 3.修改配置文件 4.创建主机清单 5.远程安装 6.远程卸载 一、运行机制 Ansible&#xff1a; ansible的核心模块 Host Inventory&#xff1a;主机清单&#xff0c;也就是被管理的主机列表 Playbooks&…

实战打靶集锦-021-glasgowsmile

提示&#xff1a;本文记录了博主的一次曲折的打靶经历。 目录 1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 手工访问4.2 目录枚举4.3 手工探查4.4 搜索EXP4.5 joomlascan4.6 用户猜测与密码爆破4.7 构建反弹shell 5. 提权5.1 优化shell5.2 枚举系统信息5.3 探查/etc/pass…

虚拟机VMware+Ubuntu配置DPDK环境并运行Helloworld

虚拟机VMwareUbuntu配置DPDK环境并运行Helloworld 文章目录 虚拟机VMwareUbuntu配置DPDK环境并运行Helloworld安装虚拟机虚拟机中安装DPDK运行Helloworld 首先需要强调的是&#xff0c;版本的影响很大&#xff0c;有可能会因为版本不匹配而导致无法成功配置DPDK环境。 安装虚拟…

【Leetcode -637.二叉树的层平均值 -671.二叉树中第二小的节点】

Leetcode Leetcode -637.二叉树的层平均值Leetcode -671.二叉树中第二小的节点 Leetcode -637.二叉树的层平均值 题目&#xff1a;给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10^(- 5) 以内的答案可以被接受。 示例 1&#xff1…

TCP服务器的C#实现

1、TCP实现类 internal class TcpServer{public Socket ServerSocket { get; set; }public Dictionary<string,Socket> Sockets { get; set; } new Dictionary<string,Socket>();public byte[] SendBuffer { get; set; }public byte[] ReceiveBuffer { get; set; …

Qt消息对话框

一、头文件及类型 #include<QMessageBox> 二、错误、信息、提示、警告演示 错误对话框 QMessageBox::critical(this,"critical","错误"); 信息对话框 QMessageBox::information(this,"info","信息"); 提问对话框 if(QMessageBo…

发布自己的第一个抖音小程序

结构与微信小程序一样 内嵌H5网页&#xff0c;适用于任何平台&#xff0c;同样也是使用web-view组件 <web-view src"https://some-domain/some/path"></web-view> 相比起来&#xff0c;它比微信小程序更加简化&#xff0c;开发会更方便了。 API查询地…

超越Java 7,迎接Java 8时代!掌握这些新特性提升你的编程技能!

大家好&#xff0c;我是小米&#xff0c;一个热衷于技术分享的小伙伴。今天&#xff0c;我将向大家介绍Java 8中的一些新特性。Java 8作为一次重大更新&#xff0c;引入了许多令人激动的新功能&#xff0c;让我们的编码变得更加简洁高效。接下来&#xff0c;我们将详细介绍这些…

【暂时解决】radio单选框的change事件执行两次

项目场景&#xff1a; 简单的单选框场景 选择国内地区&#xff0c;省市县的下拉框就显示&#xff0c;选择国外地区就隐藏。 问题描述 当我使用radio的change事件时&#xff0c;会执行两次 javascript&#xff1a; $(input[typeradio][nameoptionsRadios]).change(function …

黑产科普丨揭秘游戏黑灰产业链

自今年起&#xff0c;游戏版号已恢复常态化发放&#xff0c;游戏行业在官方发文肯定、重获资本青睐、AI降本增效等多方助力下持续回暖。暑期档将至&#xff0c;游戏厂商为了抢占更多的市场份额&#xff0c;占据更多的玩家视野&#xff0c;将有大量的游戏选择在这个时间上线。 …

datax-Oracle新增writeMode支持

1.在com.alibaba.datax.plugin.writer.oraclewriter.OracleWriter中注释此内容,以让oracle支持writeMode模式 2.在com.alibaba.datax.plugin.rdbms.writer.util.WriterUtil中,增加对oracle的判断,将getWriteTemplate修改为如下内容 public static String getWriteTemplate(List…

在文件夹中获取某个文件的绝对路径

#!/bin/bash -lpathfind $(pwd) -name *.ipaecho ${path}写成下面这样也是可以的 path$(find $(pwd) -name *.ipa)如图所示&#xff0c;Export 文件夹下有.ipa文件&#xff0c;我们目前想获取.ipa文件的绝对路径 执行结果如下 192:Jenkins liubo$ cd /Users/liubo/Desktop/…

C# 通过委托实现多个窗口之间的传值

之前用qt写的时候&#xff0c;都有信号和槽来实现&#xff0c;用C#的话应该也有类似的 大概实现的是我在父窗口当中new了两个子窗口&#xff0c;这个两个子窗口都可以将处理完的数据传递给父窗口&#xff0c;并且两个子窗口通过父窗口进行通信。 我这就按上面窗口名称来说明代…

pipeline实现二次还原

通过mode参数确定是否发布还是回滚&#xff0c;在满足rollback条件下&#xff0c;列举出我们的所有的备份的目录&#xff0c;根据回滚条件选择索要回滚的目录(目录是根据时间戳来判断创建的文件) pipeline {agent anyparameters {choice(name: mode, choices: [deploy,rollbac…

HA 自动化-通知提醒

配置->场景自动化->创建自动化 notify.notify