月度归档: 2025 年 2 月

  • JS格式化货币

    在开发和金额有关的网站应用时,货币格式化是一个常见的需求。无论是电商网站的商品价格,还是财务系统的金额显示,我们都需要将数值以规范的货币格式呈现给用户。比如,将 1234567.89 格式化为 1,234,567.89,这样不仅更美观,也更容易阅读。

    下面是一个简单而实用的 JavaScript 函数,可以帮助你轻松实现货币格式化。这个函数会将数值修约为两位小数,并添加千位分隔符,确保金额显示的规范性和一致性。

    代码实现:

    //language:js
    // 格式化货币
    function formatCurrency(value) {
        // 先将数值修约为两位小数
        let rounded = Math.round(value * 100) / 100;
        // 将数值转换为字符串
        let valueString = rounded.toString();
        
        // 检查是否有小数点
        let decimalPos = valueString.indexOf('.');
        // 如果没有小数点,添加".00"
        if (decimalPos === -1) {
            valueString += ".00";
        } else {
            // 否则, 确保小数部分至少有两位数字
            let decimalPart = valueString.substring(decimalPos + 1);
            if (decimalPart.length === 1) {
                // 如果只有一位小数, 添加一个0
                valueString += "0";
            }
        }
        
        // 添加千位分隔符
        let parts = valueString.split('.');
        parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
        
        return parts.join(".");
    }

    代码解析

    1. 修约数值
      • 使用 Math.round(value * 100) / 100 将数值修约为两位小数。这样可以确保金额的精度符合货币显示的要求。
    2. 处理小数部分
      • 将数值转换为字符串后,检查是否存在小数点。
      • 如果没有小数点,直接添加 .00,确保金额始终显示两位小数。
      • 如果小数点后只有一位数字,则补一个 0,例如将 123.5 转换为 123.50
    3. 添加千位分隔符
      • 使用正则表达式 /\B(?=(\d{3})+(?!\d))/g 在整数部分添加千位分隔符(逗号)。
      • 例如,将 1234567 转换为 1,234,567
    4. 拼接结果
      • 最后将整数部分和小数部分拼接起来,返回格式化后的字符串。

    使用示例:

    console.log(formatCurrency(1234567.89)); // 输出: "1,234,567.89"
    console.log(formatCurrency(1234.5));      // 输出: "1,234.50"
    console.log(formatCurrency(1234));       // 输出: "1,234.00"

    注意:

    如果你需要更复杂的货币格式化功能(例如支持多国货币、自定义符号等),可以考虑使用现成的库,比如 Intl.NumberFormat,它提供了更强大的国际化支持。

  • JS 获取当前时间

    在前端开发中,获取并显示当前时间是一个常见的需求。无论是用于展示网页的实时时间,还是记录用户操作的时间戳,JavaScript 都提供了简单而强大的工具来实现这一功能。下面我们将详细介绍如何使用 JavaScript 获取当前时间,并将其格式化为易于阅读的形式。

    代码实现:

    function getTime() {
    	var now = new Date();
    
    	var year = now.getFullYear();       //年
    	var month = now.getMonth() + 1;     //月
    	var day = now.getDate();            //日
    
    	var hh = now.getHours();            //时
    	var mm = now.getMinutes();          //分
    	var ss = now.getSeconds();          //分
    	document.getElementById('time').innerText = year + '年' + month + '月' + day + '日 ' + hh + '点' + mm + '分' + ss + '秒';
    }

    代码解析

    1. 创建 Date 对象
      • 使用 new Date() 创建一个 Date 对象,它会自动获取当前的系统时间。
    2. 获取年、月、日
      • getFullYear():获取完整的年份(例如 2023)。
      • getMonth():获取月份,注意返回值是 0 到 11,所以需要加 1。
      • getDate():获取当前日期(1 到 31)。
    3. 获取时、分、秒
      • getHours():获取当前小时(0 到 23)。
      • getMinutes():获取当前分钟(0 到 59)。
      • getSeconds():获取当前秒数(0 到 59)。
    4. 格式化时间
      • 将获取到的年、月、日、时、分、秒拼接成一个字符串,例如 2023年10月5日 14点30分45秒
    5. 显示时间
      • 使用 document.getElementById('time').innerText 将格式化后的时间显示在页面上。

    使用示例

    假设你的 HTML 中有一个元素用于显示时间:

    <div id="time"></div>

    调用 getTime() 函数后,页面会显示类似以下内容:

    2023年10月5日 14点30分45秒

    动态更新时间

    如果你希望时间能够动态更新(例如每秒刷新一次),可以使用 setInterval 函数:

    // 每秒调用一次 getTime 函数
    setInterval(getTime, 1000);

    这样,页面上的时间就会每秒更新一次,实现实时显示效果。

    扩展功能

    1. 补零操作
      • 如果希望时间格式更加统一(例如 14:05:09 而不是 14:5:9),可以对小时、分钟、秒进行补零操作:
    function padZero(num) {
        return num < 10 ? '0' + num : num;
    }
    
    var hh = padZero(now.getHours());
    var mm = padZero(now.getMinutes());
    var ss = padZero(now.getSeconds());
    1. 自定义格式
      • 如果需要显示其他格式(例如 2023-10-05 14:30:45),可以调整拼接方式:
    document.getElementById('time').innerText = 
        year + '-' + padZero(month) + '-' + padZero(day) + ' ' + hh + ':' + mm + ':' + ss;
    1. 国际化支持
      • 如果需要支持不同语言的时间格式,可以使用 toLocaleString() 方法:
    var options = { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' };
    document.getElementById('time').innerText = now.toLocaleString('zh-CN', options);

    适用场景

    • 网页时钟:在网页上显示实时时间。
    • 表单时间戳:记录用户提交表单的时间。
    • 日志记录:在控制台或日志中记录操作时间。
    • 倒计时功能:结合时间计算实现倒计时效果。

    注意事项

    • 时区问题new Date() 获取的是用户本地时间。如果需要显示 UTC 时间,可以使用 getUTC 系列方法。
    • 性能优化:如果页面中有大量时间显示需求,建议将时间格式化逻辑封装成工具函数,避免重复代码。
  • UEditor 基础用法:快速上手富文本编辑器

    在网页开发中,富文本编辑器是内容管理系统的核心组件之一。UEditor 是百度推出的一款开源编辑器,功能强大且高度可定制,非常适合文章发布、后台管理等场景。下面通过一段实际代码,简单说明如何快速集成 UEditor 并配置基础功能。

    第一步:引入 UEditor 文件

    首先需要下载 UEditor 的源码(可从官网获取),将相关文件放到项目目录下。假设你的编辑器文件存放在 /ueditor 路径中,在 HTML 头部引入配置文件和核心 JS:

    <!-- 引入 UEditor 配置文件和核心脚本 -->
    <script src="/ueditor/ueditor.config.js" asp-append-version="true"></script>
    <script src="/ueditor/ueditor.all.min.js"></script>

    第二步:初始化编辑器

    在页面底部或 <body> 结束前,通过 JS 初始化编辑器。以下代码创建了一个高度自适应的编辑器,并自定义了工具栏按钮:

    <script>
        var ue = UE.getEditor('container', {
            initialFrameHeight: 515,       // 初始高度
            initialFrameWidth: "100%",     // 宽度占满容器
            autoHeightEnabled: true,       // 自动撑高(根据内容)
            enableAutoSave: false,         // 关闭自动保存(避免频繁触发)
    
            // 自定义工具栏(按需删减按钮)
            toolbars: [[
                'fullscreen', 'source', '|', 'undo', 'redo', '|',
                'bold', 'italic', 'underline', 'forecolor', 'backcolor', '|',
                'insertorderedlist', 'insertunorderedlist', '|',
                'link', 'unlink', 'anchor', '|', 'image', 'inserttable', '|',
                'preview', 'searchreplace'
            ]]
        });
    </script>

    第三步:HTML 容器

    在页面中需要放置编辑器的位置添加一个 <script> 标签作为容器,并指定 id 与初始化代码中的参数一致:

    <script id="container" name="content" type="text/plain">
        这里写初始化内容(用户打开页面时会默认显示)
    </script>

    可能遇到的问题

    1. 路径错误:如果编辑器未加载,检查 JS 文件的路径是否正确。
    2. 工具栏不显示:确保 toolbars 配置的按钮名称没有拼写错误。
    3. 自适应高度失效:检查是否同时设置了 initialFrameHeight 和 autoHeightEnabled,两者需配合使用。
    4. 移动端兼容:UEditor 对移动端支持较弱,复杂场景建议搭配移动端专用编辑器。

    实用小技巧

    • 精简工具栏:示例中只保留了常用按钮,可通过增减 toolbars 中的按钮名称灵活调整。
    • 内容获取与赋值:通过 ue.getContent() 获取编辑后的内容,ue.setContent('文本') 动态修改内容。
    • 主题自定义:修改 ueditor.config.js 中的 themePath 可更换编辑器皮肤。

    如果只是需要基础的图文编辑功能,这段代码已经足够用了。更复杂的需求(比如上传文件到自己的服务器)可以查阅官方文档进一步配置。

  • Laravel 修改 API 请求前缀

    本文所使用的 Laravel 大版本为 Laravel 10。

    本来 Laravel 的 API 路由会默认自动带上api前缀,即类似于http://127.0.0.1:8000/api/get这样的形式,本来这种形式就挺美观的,也没有什么问题。但是遇到一个需求,要求在api前面加上一串固定的字符串,类似于http://127.0.0.1:8000/e10adc3949ba59abbe56e057f20f883e/api/get的形式。行吧,既然是客户的需求,那就改吧。

    首先我们找到app/Providers/RouteServiceProvider.php这个文件,在boot函数里面修改api前缀,代码如下:

    // language: php
    /**
     * Define your route model bindings, pattern filters, and other route configuration.
     */
    public function boot(): void
    {
        RateLimiter::for('api', function (Request $request) {
            return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
        });
    
        $this->routes(function () {
            Route::middleware('api')
                ->prefix('e10adc3949ba59abbe56e057f20f883e/api') // 👈 修改这行
                ->group(base_path('routes/api.php'));
    
            Route::middleware('web')
                ->group(base_path('routes/web.php'));
        });
    }

    这样,所有API路由的前缀就会自动变成e10adc3949ba59abbe56e057f20f883e/api。怎么样,Laravel 是不是很简单?!

    后记:

    时间来到2025年的2月份,这是这个月的第一篇文章,本来没什么想写的,但是再不写,这个月就要过去了,文章归档就要少一个月,就随便水一篇吧。

    已经很长很长时间没有工作了,迫于经济压力,开年以来,在做网站,对,你没看错,AI时代做网站!我知道这条路大概率走不通,但是又没有什么可做的,权且当个自我安慰吧,以至于不太焦虑。前两天有一个网站通过了 Google AdSense,但看到收入后,更焦虑了,每天几只有几分钱,还是我自己浏览的。这个也没有办法,网站缺少竞争力,没有什么流量,那么没有收入也是正常的,唉,再继续完善继续优化吧。

  • 纯 JS 动态插入 li 标签:告别 jQuery 的轻量级方案

    在网页开发中,动态修改列表内容是很常见的需求。比如实时添加待办事项、展示动态加载的数据等。如果不想依赖 jQuery 这类第三方库,通过原生 JavaScript 也能轻松实现。下面通过基础代码和扩展案例,演示如何用纯 JS 操作 DOM 动态插入列表项。

    基础实现代码

    var li = document.createElement("li");
    li.appendChild(document.createTextNode("li里的文字"));              
    document.getElementById('ul_id').appendChild(li);

    代码拆解

    1. createElement
      创建 <li> 元素,类似准备一个空容器。
    2. createTextNode + appendChild
      先创建文本节点再插入到 li,比直接写 innerHTML 更安全(避免 XSS 攻击风险)。
    3. getElementById 定位父元素
      通过 ul 的 id 找到目标列表,用 appendChild 将 li 添加为最后一个子元素。

    实际应用场景

    <!-- 示例:点击按钮动态添加列表项 -->
    <ul id="todoList">
      <li>第一项任务</li>
    </ul>
    <button onclick="addItem()">添加新任务</button>
    
    <script>
    function addItem() {
      var li = document.createElement("li");
      li.textContent = "新增任务" + Date.now(); // 更简洁的文本写入方式
      document.getElementById('todoList').appendChild(li);
    }
    </script>

  • 纯 JS 实现 AJAX

    在现代网页开发中,AJAX(Asynchronous JavaScript and XML)技术被广泛应用于实现异步请求,以便无需重新加载页面即可更新内容。下面我们展示如何用纯 JavaScript 实现 AJAX 请求。

    1. 基本的 AJAX 请求

    //language:js
    const xhttp = new XMLHttpRequest();
    xhttp.onload = function() {
        document.getElementById("demo").innerHTML = this.responseText;
    }
    xhttp.open("GET", "ajax_info.txt", true);
    xhttp.send();
    

    在这个例子中,我们创建了一个新的 XMLHttpRequest 对象,并通过 open 方法指定请求类型(GET)、请求的 URL(”ajax_info.txt”)以及是否异步(true)。当请求成功完成后,onload 事件会被触发,响应的内容会被显示在页面上的 demo 元素中。

    2. 发送表单数据并响应

    如果我们需要发送表单数据,可以使用 FormData 对象,它会自动处理表单中的所有数据。

    //language:js
    const xhttp = new XMLHttpRequest();
    xhttp.onload = function() {
        let response = JSON.parse(this.responseText);
        if (response.code == 0) {
            alert('留言成功');
        } else {
            alert(response.msg);
        }                
    }
    xhttp.open("POST", "post-message.php", true);
    
    var guestBookForm = document.getElementById("guestBookForm");
    var formData = new FormData(guestBookForm);
    
    xhttp.send(formData);
    

    在这个例子中,我们发送一个 POST 请求到 post-message.php,并通过 FormData 对象封装了表单中的数据。当 PHP 处理完请求后,返回一个 JSON 格式的响应,JavaScript 会根据返回的 code 来判断留言是否成功。

    3. PHP 处理代码

    以下是对应的 PHP 处理代码:

    //language:php
    <?php
    include 'db.php';
    
    $guestName = $_POST['guestName'];
    $message = $_POST['message'];
    
    if (empty($guestName)) {
        echo json_encode(['code' => -1, 'msg' => '昵称不能为空']);
        exit();
    }
    
    if (empty($message)) {
        echo json_encode(['code' => -1, 'msg' => '留言内容不能为空']);
        exit();
    }
    
    // 进一步的处理,如存入数据库等
    ?>
    

    在 PHP 端,我们检查了用户提交的 guestNamemessage 是否为空。如果为空,则返回相应的错误信息。

    4. 自定义 FormData

    如果需要手动构建 FormData,例如在动态生成数据时,可以这样做:

    //language:js
    const xhttp = new XMLHttpRequest();
    xhttp.onload = function() {
        let response = JSON.parse(this.responseText);                                
    }
    xhttp.open("POST", "pay.php", true);
    
    var formData = new FormData();
    formData.append("id", id);
    formData.append("unitPrice", unitPrice);
    formData.append("count", P[i]);
    
    xhttp.send(formData);
    

    通过这种方式,你可以灵活地向服务器发送任何自定义的数据。

  • claw.cloud永久3.5折VPS测评

    关注 claw.cloud 很久了,由于是新商家,想下手又有点迟疑,所以一直没有购买。

    前两天没事逛V2EX,看到有个帖子提到了 claw.cloud 的永久3.5折优惠 $12.6/年起的活动机器,看了下配置,确实很实惠。于是就在今天早上,经过一番考虑,就下单手入了一年的2C2G的产品。

    关于数据中心的选择,本来想买一个ping低的,国内访问能快点的,但是通过使用 claw.cloud 网站的提供的测试IP来看,都不太理想,香港的ping竟然达到了300多毫秒,日本机房也有170多毫秒。看到这个数字,突然意识到,这应该是绕路美国了。使用traceroute看了下,果然如此。

    claw.cloud日本线路traceroute结果

    冷静下来仔重新考了自己的需求,我买服务器主要是用来建站,而且下一步有打算做针对海外的网站,那既然如此,不管是日本还是香港,反正都要绕美国,我还不如直接买个美国数据中心的服务器好了,绕来绕去的还不如直接点。在最后一刻,果断下单了美国西部-北加利福尼亚州的服务器!

    下单后很快就开通了,让我们看一下这个美国机房的claw.cloud怎么样,首先看下去程:

    我是用的联通的宽带,可以看到去程是走的联通AS4837的骨干网,到美国落地。可以看到落地地区,果然是阿里云机房😂,不知道有没有什么内幕。

    再看一下回程:

    root@s38789:~# traceroute 112.234.151.24
    traceroute to 112.234.151.24 (112.234.151.24), 30 hops max, 60 byte packets
     1  10.59.123.62 (10.59.123.62)  0.834 ms  0.777 ms *
     2  11.73.3.225 (11.73.3.225)  2.020 ms 11.73.4.1 (11.73.4.1)  2.076 ms 11.73.3.225 (11.73.3.225)  1.949 ms
     3  11.48.250.146 (11.48.250.146)  1.526 ms 10.54.175.30 (10.54.175.30)  1.434 ms 10.54.174.254 (10.54.174.254)  1.969 ms
     4  47.246.115.6 (47.246.115.6)  1.380 ms 10.54.151.218 (10.54.151.218)  2.276 ms 47.246.114.254 (47.246.114.254)  1.243 ms
     5  * if-bundle-16.qcore2.sqn-sanjose.as6453.net (216.6.33.224)  1.809 ms *
     6  64.86.161.5 (64.86.161.5)  2.952 ms  3.200 ms  3.186 ms
     7  * 219.158.96.37 (219.158.96.37)  156.914 ms *
     8  219.158.9.214 (219.158.9.214)  150.635 ms  151.251 ms  151.240 ms
     9  219.158.96.37 (219.158.96.37)  156.924 ms  156.880 ms 219.158.8.93 (219.158.8.93)  150.404 ms
    10  219.158.123.150 (219.158.123.150)  158.002 ms 219.158.9.214 (219.158.9.214)  151.654 ms *
    11  202.102.146.26 (202.102.146.26)  163.402 ms 219.158.9.17 (219.158.9.17)  151.219 ms 61.156.156.190 (61.156.156.190)  163.182 ms
    12  219.158.3.230 (219.158.3.230)  158.527 ms * *
    13  * * 61.156.156.190 (61.156.156.190)  163.932 ms
    14  * * *
    15  * * *
    16  * * *
    17  * * *
    18  * * *
    19  * * *
    20  * * *
    21  * * *
    22  * * *
    23  * * *
    24  * * *
    25  * * *
    26  * * *
    27  * * *
    28  * * *
    29  * * *
    30  * * *

    从这个traceroute输出里面,一眼看到了219开头的地址,这是中国电信的骨干网,AS号是AS4134。总体来说也还行吧,中规中矩。

    再来看一下ping的延迟和稳定性:

    claw.cloud ping 截图

    这个ping看起来就很香了,160+的延迟可以和搬瓦工DC9的GIA线路相媲美了,延迟倒是其次,最主要的是稳定,ping了有半个多小时,全程无丢包,不过这是白天,等晚上再试一下,如果晚上还是这么稳定,那才是真厉害。

    测完了线路,下面在机器内跑一下测评脚本看下情况,我使用的是Bench.sh的测试脚本,执行代码wget -qO- bench.sh | bash,下面看下结果:

    claw.cloud Bench.sh 测评结果

    可以看到,使用的是KVM虚拟化技术,40G硬盘,2G内存,Organization属于阿里巴巴(阿里云)👍。

    硬盘IO在200MB左右,中规中矩;网络测速都还不错,但是香港0.34Mbps是个什么情况🤣。

    整体来说这个VPS很不错,尤其对于做站来说,最主要的是便宜,主打一个性价比,一年低至12.6,还要什么自行车。

    最后补个链接,活动页面在这里:https://claw.cloud/promotion (无aff),有需要的可以自行购买。

  • JS判断某个对象是否有某个属性

    在 JavaScript 中,我们可以使用 hasOwnProperty 方法来判断某个对象是否拥有指定的属性。这个方法可以帮助我们区分对象本身的属性和从原型链继承的属性。

    1. 使用 hasOwnProperty 方法

    hasOwnProperty 是 Object.prototype 上的方法,它不会检查原型链,因此它是最可靠的方式来判断对象自身是否包含某个属性。

    示例代码:

    const obj = {
        name: "张三",
        age: 25
    };
    
    console.log(obj.hasOwnProperty("name")); // true
    console.log(obj.hasOwnProperty("age"));  // true
    console.log(obj.hasOwnProperty("gender")); // false

    2. in 运算符

    in 运算符可以用于检查对象及其原型链上是否存在某个属性。

    示例代码:

    const obj = {
        name: "李四"
    };
    
    console.log("name" in obj);  // true
    console.log("toString" in obj); // true,因为 `toString` 是 Object.prototype 上的方法

    3. Object.hasOwn(ES2022 新增)

    在 ES2022 中,JavaScript 引入了 Object.hasOwn,它是 hasOwnProperty 的更安全替代方法。

    示例代码:

    const obj = {
        city: "北京"
    };
    
    console.log(Object.hasOwn(obj, "city")); // true
    console.log(Object.hasOwn(obj, "country")); // false

    4. 何时使用哪种方法?

    • hasOwnProperty:适用于检查对象自身是否拥有某个属性,避免检查原型链上的属性。
    • in 运算符:如果想要检查某个属性是否存在于对象或其原型链上,可以使用 in
    • Object.hasOwn:如果环境支持 ES2022,建议使用 Object.hasOwn,因为它不会被 hasOwnProperty 可能被覆盖的问题影响。

    5. 注意事项

    如果某个对象的 hasOwnProperty 方法被覆盖,调用 Object.prototype.hasOwnProperty.call(obj, key) 仍然可以检查属性:

    const obj = {
        hasOwnProperty: function() {
            return false;
        },
        id: 1001
    };
    
    console.log(obj.hasOwnProperty("id")); // false(被覆盖)
    console.log(Object.prototype.hasOwnProperty.call(obj, "id")); // true

    6. 结论

    在 JavaScript 中,判断对象是否具有某个属性的方法有多种,通常推荐使用 hasOwnPropertyObject.hasOwn 进行安全检查。对于特殊情况,可以结合 in 运算符或者 Object.prototype.hasOwnProperty.call 来确保可靠性。

    希望这篇文章对你有所帮助!

  • 把JS数组赋值给表单里的字段

    在实际开发中,我们经常需要将 JavaScript 数组的值提交到表单中。本文介绍如何将一个 JS 数组 selectedTextArray 赋值给表单中的隐藏字段,以便在提交时传输到服务器。

    1. HTML 结构

    我们使用一个 ID 为 form 的表单,并在 onclick 事件中调用 update() 方法来动态添加隐藏字段。

    <form class="form-horizontal" id="form" action="/role-permission/update/{{ $role->id }}" method="post">
        @csrf
        <div class="box-body">                  
            <div class="form-group">
                <div class="col-sm-12">
                    <div id="tree"></div>
                </div>
            </div>         
        </div>
        <div class="box-footer">
            <button type="submit" class="btn btn-primary pull-right" onclick="return update();">保存</button>
        </div>
    </form>

    2. JavaScript 代码

    update() 方法中,我们遍历 selectedTextArray 数组,并动态创建 input 隐藏字段,将其添加到表单中。

    function update() {
        // 假设 selectedTextArray 是一个已有的数组
        let selectedTextArray = ["read", "write", "execute"]; // 示例数据
        
        let form = document.getElementById("form");
        
        // 清除已有的隐藏字段,避免重复提交
        document.querySelectorAll("input[name='permissions_array[]']").forEach(el => el.remove());
        
        // 遍历数组并创建隐藏字段
        for (let i = 0; i < selectedTextArray.length; i++) {
            let item = document.createElement("input");
            item.type = "hidden";
            item.name = "permissions_array[]";
            item.value = selectedTextArray[i];  
            form.appendChild(item);
        }
    
        return true; // 允许表单提交
    }

    3. 关键点解析

    • item.name = "permissions_array[]"; 这一行代码的作用是确保数据以数组的形式提交到服务器。
    • document.querySelectorAll("input[name='permissions_array[]']").forEach(el => el.remove()); 这行代码确保每次点击提交按钮时都会清除先前的隐藏字段,避免重复数据。
    • 通过 appendChild(item); 将新创建的隐藏 input 字段添加到表单中。

    4. 提交到服务器的示例数据

    假设 selectedTextArray 包含 ["read", "write", "execute"],提交后服务器接收到的数据格式如下:

    {
        "permissions_array": ["read", "write", "execute"]
    }

    5. 结论

    通过 JavaScript,我们可以动态地为表单添加隐藏字段,并将数组数据以正确的格式提交到服务器。这样可以方便地传输多选数据,如权限管理、标签选择等场景。

  • 根据 MDF 文件查询数据库版本

    在 SQL Server 中,MDF(主数据库文件)包含了数据库的版本信息。如果需要查询 MDF 文件对应的 SQL Server 版本,可以使用 PowerShell 读取文件中的特定字节数据。

    1. 使用 PowerShell 查询 MDF 版本

    PS > get-content -Encoding Byte "C:\path\to\database.mdf" | select-object -skip 0x12064 -first 2
    PS > [int]($_[0] + $_[1] * 256)

    注意,复制命令不要复制前面的PS >

    2. 解析数据库版本

    上述 PowerShell 命令的逻辑如下:

    1. get-content -Encoding Byte "C:\path\to\database.mdf" 以字节形式读取 MDF 文件。
    2. select-object -skip 0x12064 -first 2 跳过前 0x12064 个字节,并获取接下来的 2 个字节(这两个字节存储了 SQL Server 版本信息)。
    3. $_[0] + $_[1] * 256 计算版本号。

    例如,我们执行下面的命令:

    get-content -Encoding Byte "d:/B2B.mdf" | select-object -skip 0x12064 -first 2

    命令返回:

    149
    2

    那么,我们用149+2*256来计算版本号,得到结果是661,然后到下表里面去查找即可。

    如果不想手动计算,也可以使用下面的三行命令,让程序自动计算版本号:

    PS > $bytes = Get-Content -Encoding Byte "d:/B2B.mdf" | Select-Object -Skip 0x12064 -First 2
    PS > $version = $bytes[0] + ($bytes[1] * 256)
    PS > $version

    3. 版本号对照表

    计算出的整数版本号可以对照以下 SQL Server 版本表:

    版本号SQL Server 版本
    515SQL Server 7.0
    539SQL Server 2000
    611SQL Server 2005
    655SQL Server 2008
    661SQL Server 2008 R2
    706SQL Server 2012
    782SQL Server 2014
    852SQL Server 2016
    869SQL Server 2017
    904SQL Server 2019
    921SQL Server 2022

    4. 结论

    通过 PowerShell 读取 MDF 文件的特定字节,我们可以快速确定数据库版本,无需启动 SQL Server 实例。此方法适用于数据库管理员或运维人员排查数据库兼容性问题。