Vue CDN 模式引用到razor模板附加JS常用数据操作

小占时光 2024-10-30 09:53:07 989


基础知识

        在我开始使用C#开发web开始,大多都是使用Razor模版开发html页面。很少会想java这样将前后端分离,之前进入过一家公司,在本地也算是一家大的联网公司了。他们的软件最开始是使用C#开发的,后面有一部分开始使用java开发,这样公司里面就招聘前端,java,C#。C#的开发人员就是前后端需求都是连在一起,java的需求就是拆分开,他们只做后端。其实我们也可以前后端分离的,但是还是自己默默地干了。像C#这样服务端渲染(SSR)和前后端分离后的前端渲染(CSR) 各自有着自己的优缺点,结合自己的需求和可调动资源选择。

 

服务端渲染(SSR)

工作方式:服务器生成页面的 HTML 内容,然后将其发送给客户端。客户端直接接收并显示已渲染的页面。

优点:
更快的首屏渲染:SSR 提供一个完整的 HTML 页面,客户端无需等待大量 JavaScript 加载和执行,因此首屏渲染速度较快。
有利于 SEO:搜索引擎可以直接抓取完整的 HTML 内容,使得 SSR 网站更易于被搜索引擎索引。
更好的兼容性:适用于一些性能较低的设备或不支持 JavaScript 的浏览器,用户能获得完整的页面体验。

缺点:
服务器压力较大:每个用户请求都会触发服务器生成 HTML,容易导致高并发下服务器压力增加。
交互性较低:需要与前端代码结合才能实现复杂的交互,前后端切换时可能有短暂的空白页面或跳转闪烁。
开发复杂性:需要将前后端逻辑整合,常常依赖框架来实现 SSR(如 Next.js、Nuxt.js)以简化开发。

适用场景:
网站内容主要为静态内容,页面内容变化较少的项目。
需要快速响应和 SEO 优化的网站,如新闻、博客、电子商务网站首页等。

前端渲染(CSR)

工作方式:服务器发送一个基础的 HTML 文件,随后加载 JavaScript,并在浏览器中生成和渲染页面内容。

优点:
更好的用户交互:页面可以通过 JavaScript 实现复杂的交互效果,不需要重新加载整个页面,用户体验流畅。
减少服务器负担:页面渲染和数据操作在客户端进行,减少了服务器的压力。
更灵活的前端架构:CSR 更适合构建高度动态、交互复杂的应用(如单页应用,SPA),可轻松实现前端组件复用。

缺点:
首屏加载较慢:初次加载需要传输和执行大量 JavaScript,导致页面在首屏上渲染速度变慢。
SEO 难度增加:因为页面内容是在客户端生成的,搜索引擎抓取器可能无法完全索引页面内容。
需要较好的客户端性能:依赖于客户端的性能,设备较慢或网络不佳的用户可能会体验卡顿。

适用场景:
交互性和动态性较高的单页应用,如社交网络、任务管理、在线文档编辑等。
用户登录后显示个性化内容的应用,例如管理控制台、CRM、仪表盘。

 

VUE 的使用(CDN引用)

     使用Razor模版的一个痛点就是“需要与前端代码结合才能实现复杂的交互”,如果交互多,则需要写很多js代码,维护起来特别累。对于一些复杂页面还是选择使用vue来实现,这样页面交互会轻松一点。vue 的使用使用有两种情况,一种是Vue CLI使用 Vue CLI 或 Vite 创建项目,这些工具会自动配置好 Webpack 或 Vite 等打包工具。VUE有多个版本,每个版本语法不一样(如果照着写了效果不一样,记得检查版本),下面使用的是VUE3。

官网文档地址:➤ https://cn.vuejs.org/guide/introduction.html

# 使用 Vue CLI 创建项目
npm install -g @vue/cli
vue create my-project

# 使用 Vite 创建项目
npm create vite@latest my-project --template vue

另一种是CDN 引用,直接在页面上引用vuejs即可。

<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
<div id="app">
    {{ message }}
</div>
<script>
    const app = Vue.createApp({
        data() {
            return {
                message: 'Hello Vue!'
            }
        }
    })
    app.mount('#app')
</script>

使用第一种Vue CLI方式需要编译打包后才能访问,第二种CDN引用不需要编译,使用比较简单。对于C# MVC 项目,本来没有做前后端分离,就是某个页面交互比较复杂,所以选择CDN引用的方式

对于vue 的使用照着官网(➤ https://cn.vuejs.org/guide/introduction.html)写就行了,这里就不列出来了,介绍一下没有记录的。

 

第三方控件使用

CDN引入和创建vue项目不一样,引用其他vue控件时,需要umd.js,不是所有控件都会提供。

<script src="/vuedraggable/vuedraggable.umd.js"></script>

createApp({
    components: {
        vuedraggable,
    },
    data() {
        return { items: [],}
    },
})
<vuedraggable v-model="items" item-key="id" animation="30" :sort="true" @@end="dragEnd" class="col-md-12 row me-0">
    <template #item="{ element }">
        <div>
            <input v-bind:id="element.id" v-bind:data-sort="element.sort" v-if="element.isEdit"
                v-model="element.name" />
            <span v-else class="media-title">{{element.name}} </span>
        </div>
    </template>
</vuedraggable>

UMD(Universal Module Definition)是一种模块化模式,它可以让一个库兼容多种 JavaScript 模块加载系统,适用于浏览器、CommonJS 和 AMD 环境。UMD 格式使得组件或库可以在各种环境下使用,通常包括以下几种形式:
浏览器直接引入:在没有模块系统的浏览器环境中,通过 <script> 标签加载 UMD 格式的库,全局会自动添加一个变量,如 VueTreeselect,可以直接在代码中使用。
CommonJS:在 Node.js 环境中使用 require 引入模块。
AMD:在 AMD 模块加载器中使用 define。
UMD 的特点
跨环境兼容:适用于浏览器、Node.js、AMD 等不同环境。
常见于 CDN 资源:许多组件库(如 Vue 和第三方库)提供 UMD 格式,便于通过 CDN 直接引入,尤其适合在浏览器环境中使用。
是否所有组件都有 UMD 格式?
并非所有组件或库都会提供 UMD 格式。是否提供取决于库的开发者以及项目的使用场景:
提供 UMD:许多主流组件库(如 Vue、Vue Router、Axios、Lodash 等)通常会提供 UMD 格式,方便直接在浏览器中引入。
不提供 UMD:一些现代的、偏向模块化设计的库可能仅提供 ESM(ES Modules)或 CommonJS 格式,因为 UMD 需要额外的代码逻辑来兼容不同环境,且在模块化已普及的环境下,UMD 的需求逐渐减少。
如果需要直接在 HTML 中通过 CDN 引入某个组件,可以查看该库的官方文档,通常会明确说明是否提供 UMD 格式。

自己创建组件

     自己创建组件和官网上一样。这里组件写成一个变量形式,直接在components中使用即可。

html代码

<div>
    <my-component></my-component>
</div>

js 代码

 <script>
    // 定义 MyComponent 组件
    const MyComponent = {
      template: `<div>Hello from MyComponent</div>`
    };

    // 创建 Vue 应用实例
    const app = Vue.createApp({
      components: { MyComponent }
    });

    // 挂载应用到页面中的 #app 元素
    app.mount('#app');
  </script>

控件的使用确实比较麻烦,如果使用控件比较多。还是单独创建一个vue项目,开发好编译后放在项目下面也是可以的,只是这样要多出一些操作。

 

数据操作(增、删,改,查,计算)

       数据操作的方式大多都是js中的方法,即使没有使用vue也可以在引用了jq 的页面中使用。所有页面的交互,除了css的一些动画,其实也就是数据的改变。下面介绍一下实战过程中需要使用到的一些数据(数组)操作,同时也是记录方便自己查找,开发方向比较多,过几天又忘记了。列表中添加一条记录,vue中列表其实就是数组v-for=“items” 得到的,那么只要在items数组中添加数据即可。

数组中添加数据 

1、push() 在数组末尾添加一个或多个元素(经常使用)

let arr = [1, 2, 3];
arr.push(4); // arr 变成 [1, 2, 3, 4]
arr.push(5, 6); // arr 变成 [1, 2, 3, 4, 5, 6]

2、unshift() 在数组开头添加一个或多个元素。

let arr = [1, 2, 3];
arr.unshift(0); // arr 变成 [0, 1, 2, 3]
arr.unshift(-2, -1); // arr 变成 [-2, -1, 0, 1, 2, 3]

3、splice() 在数组中指定位置插入一个或多个元素。( 可以新增,也可以删除)

/*删除元素*/
var items = ["小明", "大明", "高明", "神明"];
items.splice(2, 1); // 删除从位置 2 开始的一个元素 (高明)
// items结果 为: "小明", "大明",  "神明"

/*添加和删除元素*/
var items =  ["小明", "大明", "高明", "神明"];
items.splice(2, 1, "新明1", "新明2"); // 在位置 2 删除一个元素,并添加两个新元素
// items结果 为:"小明", "大明","新明1", "新明2", "神明"

/*只添加元素*/
var items =  ["小明", "大明", "高明", "神明","小占时光"];
items.splice(2, 0, "新明1", "新明2"); // 在位置 2 删除一个元素,并添加两个新元素
// items结果 为:小明", "大明", "新明1", "新明2","高明", "神明","小占时光"

4、concat()用于连接数组,返回一个新的数组。

let arr = [1, 2, 3];
let newArr = arr.concat(4, 5); // newArr 为 [1, 2, 3, 4, 5]

5、使用索引直接添加

let arr = [1, 2, 3];
arr[3] = 4; // arr 变成 [1, 2, 3, 4]
arr[10] = 11; // arr 变成 [ 1, 2, 3, 4, <6 empty items>, 11 ]

6、 Array.from()  创建一个新数组并添加新元素

let arr = [1, 2, 3];
let newArr = Array.from([...arr, 4, 5]); // newArr 变成 [1, 2, 3, 4, 5]
// 生成从 1 到 6 的数组
const arr = Array.from({ length: 6 }, (_, index) => index + 1);

Array.from({ length: 6 }) 创建了一个长度为 6 的数组,数组的元素是 undefined。
第二个参数是一个映射函数 (_, index) => index + 1,它接受两个参数:当前元素的值(在这里是 undefined),和元素的索引。通过这个函数,索引 0 被映射为 1,索引 1 被映射为 2,以此类推,直到索引 5 映射为 6。

添加数据方法用的比较多的就是push方法,很多时候都只是在数组后面添加数据。太多了记不住,就记得push,基本的小功能就可以完成了。

 

数组中移除数据  

1、pop() 移除数组末尾的一个元素,并返回该元素。

let arr = [1, 2, 3];
let removed = arr.pop(); // removed 为 3,arr 变成 [1, 2]

2、shift() 移除数组开头的一个元素,并返回该元素。

let arr = [1, 2, 3];
let removed = arr.shift(); // removed 为 1,arr 变成 [2, 3]

3、splice() 同新增的 splice,参考前面的例子即可

4、filter() 根据条件过滤数组中的元素,生成一个新的数组。

let arr = [1, 2, 3, 4, 5];
let newArr = arr.filter(item => item !== 3); // 过滤掉 3,newArr 为 [1, 2, 4, 5]

5、delete() 可以使用 delete 删除数组中的某个元素,但会留下 undefined 项。

let arr = [1, 2, 3];
delete arr[1]; // arr 变成 [ 1, <1 empty item>, 3 ]

6、slice() 不会修改原数组,而是返回一个新数组

let arr = [1, 2, 3, 4, 5];
let newArr = arr.slice(1); //  [2, 3, 4, 5]
let newArr = arr.slice(0, arr.length - 1); // [1, 2, 3, 4]
// 提取从索引 0 到索引 3(不包括 3)的元素
let newArr2 = arr.slice(0, 3); // 输出: [1, 2, 3]

start(可选): 提取起始处的索引(从 0 开始)。如果省略,则默认为 0。
end(可选): 提取终止处的索引(从 0 开始)。如果省略,则提取到数组末尾。

 

删除操作中使用比较多的是 splice,两种方式我用得多一点

/*删除指定id 的记录*/
let obj={id:xxx,...}  
let itemIndex = 0;
  arr.forEach(function (item, index) {
      if (item.id == obj.id) {
          itemIndex = index;
      }
  });

  // 移除指定id 的数据
  arr.splice(itemIndex, 1);
/*删除某一个元素*/ 
var index = items.indexOf(item);
 items.splice(index, 1);

 

数组中数据值修改

1、使用索引直接修改

let arr = [1, 2, 3, 4, 5];
arr[2] = 10; // 修改索引为 2 的元素(原为 3),现在变为 10
console.log(arr); // 输出: [1, 2, 10, 4, 5]

修改数据,一般是绑定到v-model上。如果需要修改某一个,会直接传递item 对象,直接修改就行。如果是批量修改则会使用forEach循环。

查询数组中的数据

1、filter()  方法可以根据条件过滤数组,返回满足条件的所有元素的新数组

let arr = [5, 12, 8, 130, 44];

// 查询所有大于 10 的元素
let result = arr.filter(item => item > 10);
console.log(result); // 输出: [12, 130, 44]

2、find() 方法返回数组中第一个满足条件的元素,如果没有找到则返回 undefined。

let arr = [5, 12, 8, 130, 44];

// 查询第一个大于 10 的元素
let result = arr.find(item => item > 10);
console.log(result); // 输出: 12

3、some() 方法测试数组中是否至少有一个元素满足条件,如果是,则返回 true,否则返回 false。

let arr = [5, 12, 8, 130, 44];

// 检查是否有大于 10 的元素
let hasGreaterThanTen = arr.some(item => item > 10);
console.log(hasGreaterThanTen); // 输出: true

4、every() 方法测试数组中的所有元素是否都满足条件,如果是,则返回 true,否则返回 false。

let arr = [5, 12, 8, 130, 44];

// 检查所有元素是否都大于 0
let allGreaterThanZero = arr.every(item => item > 0);
console.log(allGreaterThanZero); // 输出: true

划重点,查询操作中最常用的是 filter()

 

数组的批量操作和遍历

1. for 循环

let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]); // 访问每个元素
}

2、$.each()

let arr = [1, 2, 3, 4];
$.each(arr, function(index, value) {
    console.log("Index: " + index + ", Value: " + value);
});

3、forEach() 方法

let arr = [1, 2, 3, 4, 5];
arr.forEach((item, index, array) => {
    console.log(item, index); // item: 当前元素,index: 当前索引,array: 原数组
});

$.each:
属于 jQuery 库,是一个函数,用于遍历数组或对象。
提供了一种一致的方式来处理数组和对象的遍历。

forEach:
是 JavaScript 原生数组的方法(从 ECMAScript 5 开始引入)。
仅用于遍历数组,不支持对象。

(简单操作:页面使用forEach报错,那么使用$.each就行了,还报错就检查jquery是否引入)

4、map() 方法对数组的每个元素执行指定的函数,返回一个新数组。适合需要对数组元素进行转换的场景。(和C# LINQ中Select一样)

let arr = [1, 2, 3, 4, 5];
let newArr = arr.map((item, index) => item * 2);
console.log(newArr); // 输出: [2, 4, 6, 8, 10]

5、filter() 方法创建一个新数组,包含所有满足条件的元素。(遍历所有元素进行判断)

let arr = [1, 2, 3, 4, 5];
let filteredArr = arr.filter(item => item > 2);
console.log(filteredArr); // 输出: [3, 4, 5]

6、 some() 前面已有介绍

7、every() 前面已有介绍

8、reduce() 方法对数组中的每个元素执行一个函数,最终计算出一个值。可以用于聚合操作。(求和函数)

let arr = [1, 2, 3, 4, 5];
let sum = arr.reduce((accumulator, current) => accumulator + current, 0);
console.log(sum); // 输出: 15

参数:
callback:要执行的函数,接收四个参数:
accumulator:累加器,累积回调的返回值。
current:当前元素。
index (可选):当前元素的索引。
array (可选):原数组。
initialValue (可选):指定初始值,如果未提供,则使用数组的第一个元素作为初始值。

 

vue 计算属性

        前面介绍的数组操作只要引用了js都可以使用,下面介绍一下vue的计算属性(下面例子都是vue3的,vue2不适用)。

<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
<div id="app">
    {{ message }}
</div>
<script>
    const { createApp, computed } = Vue
    var appObj = createApp({
        data() {
            return {
                message: 'Hello Vue!',
                count:0,
                items:[1,2,3]
            }
        },
        mounted(){
            var self = this;
            this.count = computed(()=>{

                return self.items.reduce((sum, next) => { return sum + Number(next) }, 0);
            })
        }
    })
    app.mount('#app')
</script>

计算属性的好处,不管数据怎么变化,结果都是按公式计算出来的结果。例如上面count,不管数组中的值是增加了还是减少了,都是数组中的元素求和。修改值的时候就不用考虑重新计算,当然这个代码官网也有介绍,下面需要注意的是:

正确写法:

var obj1 = { sort: 0, start: 0, end: 0, count: 0 }
items.push(obj1)

// 最新加入的对象
var obj2 = items[(section.rules.length - 1)];

obj2.start = computed(() => {
    var start = 0;
    items.forEach((item) => {
        if (item.sort < rule.sort) {
            start += Number(item.count);
        }
    });
    return start;
});

错误写法:

var obj1 = { sort: 0, start: 0, end: 0, count: 0 }
obj1.start = computed(() => {
    var start = 0;
    items.forEach((item) => {
        if (item.sort < rule.sort) {
            start += Number(item.count);
        }
    });
    return start;
});

items.push(obj1)

为什么第二种是错误的写法呢?如果在普通 JavaScript 对象上直接使用 computed,Vue 的响应式系统无法自动追踪数据变化。

写法一种的obj1和obj2已经不是同一个类了

对于比较复杂,且数据结果层次很深的情况,要注意,计算属性不能再普通的js对象上添加,不会生效。现将数据添加到集合中,再监听计算。

扩展

使用 .split() 和 .join() 对字符串进行分割和重组。

let arr = ["我是", "小占", "时光"];
let str = arr.join(","); // 使用逗号 "," 作为分隔符
console.log(str); // 输出: "我是,小占,时光"

// 将字符串再次分割为数组
let splitArr = str.split(","); // 按逗号分割字符串
console.log(splitArr); // 输出: ["我是", "小占", "时光"]

三个点的使用(...)

... 是一种称为 扩展运算符(spread operator) 或 剩余参数(rest parameter) 的特殊语法,用于数组、对象、函数参数等多种场景。

个人总结就是将原来的数组和对象打散,变成新的数组和对象。

数组中使用

let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let combinedArr = [...arr1, ...arr2]; // 合并成一个新数组
console.log(combinedArr); // 输出: [1, 2, 3, 4, 5, 6]

let copiedArr = [...arr1]; // 创建 arr1 的浅拷贝
console.log(copiedArr); // 输出: [1, 2, 3]

对象中使用

let obj1 = { a: 1, b: 2 };
let copiedObj = { ...obj1 }; // 创建 obj1 的浅拷贝
console.log(copiedObj); // 输出: { a: 1, b: 2 }

对象中使用详细介绍一下,在vue中对象都是引用对象,讲一个对象赋值给了其他位置,这个对象其他位置发生改变,所有关联地方都会改变,这个时候就可以用... 得到新对象用于赋值,这样就可以互不干扰。

还有一个用法,可以在新对象中添加属性。假如api接口获得了一个集合,我要在集合中选择需要的数据,那么集合对象就需要有一个 ‘isChecked’属性用于绑定checkbox控件,后端不会带此属性给前端,那这个时候就可以使用... 来添加型属性。

// data 为ajax 获取到的后端数据
this.items = data.map(item => {
    return { ...item, isChecked: false };
});

 

最后一次修改 : 2025/1/23 上午3:11:08

优秀
123
分享
123
奶茶
123
文章版权声明:版权归原作者(小占时光)所有。未经明确书面许可,严禁任何个人或组织以任何形式进行商业性或非商业性的使用、转载或抄袭。
评论