1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 实战Vue:Mint UI移动端购物商城

实战Vue:Mint UI移动端购物商城

时间:2022-07-21 19:30:32

相关推荐

实战Vue:Mint UI移动端购物商城

文章目录

UI组件库下载安装配置UI组件库使用mint-ui组件库中组件短消息提示框iconfont确认框创建空组件实现提示框案例mint-ui表单组件输入框开关组件单选列表表单组件案例mint-ui组件库面板底部导航条面板底部导航条案例组件中数据传递(父组件传递数据子组件) 父组件在模板中调用子组件微信消息列表功能案例用户登录案例安装xampp 软件安装nodejs 软件创建服务器目录下载安装第三方模块app.js功能一 : 用户登录验证(用户登录服务器端(node))无法访问服务器错误一脚手架概念案例的脚手架文件 Login.vue发送ajax请求 [脚手架8080-->服务器4000]安装使用axiossession对象app.js 功能一 -- 功能三无法访问服务器错误二商品列表app.js功能二 : 显示商品列表-(分页)npm run serve报错将商品添加至购物车功能app.js功能三 : 将商品添加至购物车app.js 中打开浏览器报错脚手架 添加购物车组件Product.vue常见错误一app.js功能四 : 查询(指定用户)购物车列表app.js 功能一 -- 功能五脚手架 购物车组件Cart.vue查询购物车组件 Cart.vue常见错误二app.js功能五:删除购物车中一条商品信息全选按钮 Cart.vue删除选中的商品 Cart.vue购物车中商品数量 vuexvuex安装配置与使用查询全选删除购物车 Cart.vueapp.js 功能一 -- 功能六

UI组件库

组件库作用:提高开发效率

PC端组件库

饿了么 elementUI

/#/zh-CN/

移动端组件库

饿了么 mintui

https://mint-ui.github.io/docs/#/zh-cn2

有赞: vant[vue 移动端/小程序项目]

https://youzan.github.io/vant-weapp/#/

滴滴 cube-ui

https://didi.github.io/cube-ui/#/zh-CN/

下载安装配置UI组件库

①下载脚手架 : 自己写项目的时候自己创建新脚手架-(创建|打包)

②启动脚手架

(1)启动位置脚手架文件package.json右键终端 npm run serve 回车 (终端node cmd都可以,不能powershell)

(2)打开浏览器http://127.0.0.1:8080/#/第一个 / 当前项目 , #/ 后面是组件路径

mint UI组件库下载与配置

③ 下载组件库

在脚手架根目录下执行安装指令

脚手架文件目录打开cmd →npm i mint-ui -S// i (install)安装组件 , -S 保存组件名称与版本至package.json文件中

④配置组件库 main.js (配置第三方组件库)

(1)将组件库中所有组件引入到当前项目中

import MintUI from "mint-ui"//mint-ui文件夹

(2)单独引入mint-ui组中样式文件

import "mint-ui/lib/style.css"

(3)将组件库注册Vue对象

Vue.use(MintUI);

(4)new Vue中自带store(存储对象)要删除不然会报错

使用mint-ui组件库中组件

短消息提示框

功能:显示消息框其中有一段文字,默认3秒后隐藏

作用:提示用户消息(删除成功;添加成功;添加失败;…)

简洁语法: this.$ toast(“一段文字”);

标准语法:this.$toast({})

iconfont

遇到问题:在消息框中显示图标(有意义小图片)Mint-ui组件库提供图标外观不精美,不满足用户需求

解决问题:专业图标网站 / 阿里巴巴下 下载图标方式

方式一:直接下载图标对应图片 (建议:使用图片少量)

方式二:将多个图标保存字体图标文件 ttf (建议:使用图片大量)

①点击图标对应购物车按钮 (选择图标) 纯色

②点击购物车按钮(下载代码)download.zip(包含css,ttf文件) ttf 是字体图标文件

使用图标字体

③在脚手架src目录下创建文件夹font(保存图标字体)

将下载的download.zip内容解压缩,打开内部的文件(demo.css,iconfont.css…)复制到font文件夹中

④在main.js 引入图标字体样式文件 iconfont.css

全局引入图标字体,可以在任何组件中使用图标

⑤在指定组件中调用图标

iconClass:”字体class 指定图标class名”iconClass:"iconfont icon-meishi"

如何调整图标大小,修改字体大小图标跟随变大 iconfont.css 文件第12行font-size:16px

确认框

功能:显示一个确认框只有用户操作后隐藏

#重要性高一些

作用:是否删除指定数据,用户名格式有误

(1)this.$messagebox("标题","内容");

(2)this.$messagebox.confirm("确认消息")

.then(res=>{})当用户选择确认按钮回调函数

.catch(err=>{})当用户选择取消按钮回调函数

(3)this.$messagebox.prompt("输入消息文件")

.then((value)=>{})当用户输入成功回调函数

.catch(err=>{})输入失败

创建空组件实现提示框案例

(1)创建空组件 src/components/2.21/exam/exam01.vue

(2)为空组件指定访问路径 router.js path:"/exam01"

(3)通过浏览器地址栏 http://127.0.0.1:8080/#/exam01

第一步 : 右键package.json终端打开npm run serve启动脚手架

第二步 :src文件夹下的components里创建组件文件

src/components/2.21/exam/exam01.vue

<template><div><h3>mintui练习组件exam01.vue</h3><!-- 添加一个按钮,当用户点击按钮时显示消息提示框 --><button @click="openToast">显示消息框</button><!-- 添加一个按钮,当用户点击按钮时显示确认框 --><button @click="openAlert">显示确认框</button></div></template><script>export default {//2:添加一组函数methods:{//2.1:添加显示消息提示框函数openToast(){//console.log(123);// 2.2:显示短消息提示框:默认3s后结束//this指当前组件对象exam01.vuethis.$toast({message:"添加成功",//显示的文字position:"top",//文字位置iconClass:"iconfont icon-diannao"//指定字体图标 电脑图标});},//添加显示确认消息函数openAlert(){// 确认消息确定// this.$messagebox("消息","用户名格式不正确")//确认按钮消息 确定 取消// this.$messagebox.confirm("是否删除指定数据")//跟上面的只能用一个// .then(res=>{// console.log("确认")//确认后的回调函数// })// .catch(err=>{// console.log("取消")// })// 输入框this.$messagebox.prompt("请输入")//跟上面的只能用一个.then(value=>{console.log(value)//确认后的回调函数}).catch(err=>{console.log(err)})},}}</script>

第三步:为新建组件文件指定访问路径, 在router文件夹下index.js文件中 path:"/exam01"

src/router/index.js

import Vue from 'vue' //引入Vue对象import VueRouter from 'vue-router' //引入路由//引入自定义组件//1.引入组件exam01.vueimport exam01 from "../components/2.21/exam/exam01.vue"Vue.use(VueRouter)//将路由对象注册V//配置组件-:访问路径const routes = [{path: '/exam01',component: exam01}]//打开浏览器地址:http://127.0.0.1:8080/#/exam01const router = new VueRouter({routes})export default router

第四步: main.js里引入新组件exam01.vue所需组件库

main.js

import Vue from 'vue'import App from './App.vue'import router from './router'import store from './store'Vue.config.productionTip = false//功能一:引入和配置mint-ui组件库//1:引入mint-ui所有组件import MintUI from "mint-ui"//2:单独引入mint-ui样式文件import "mint-ui/lib/style.css"//3:将mint-ui对象注册Vue实例Vue.use(MintUI);//功能二:引入图标字体中样式文件,使所有自定义组件均可使用import "./font/iconfont.css"new Vue({router,//store, //存储对象删除render: h => h(App)}).$mount('#app')

mint-ui表单组件
输入框

组件:<mt-field></mt-field>

属性:label:左侧标签 ,type:text password … ,attr:原生属性

①创建组件

src/components/2.21/exam/exam02.vue

<template><div><h3>表单组件</h3><!--添加用户名输入框--><mt-field label="用户名" placeholder="请输入用户名"v-model="uname":attr="{maxlength:10,autofocus:true}"></mt-field><!-- mt是 mint-ui缩写 , v-model双向绑定 , :attr="{原生属性写里面}" ,autofocus闪烁光标 --><!--添加密码输入框--><mt-field label="密码"placeholder="请输入密码"v-model="upwd"></mt-field><!--登录按钮--><mt-button @click="login">登录</mt-button> </div></template><script>export default {data(){//组件共享数据保存data 11return {uname:"", //双向绑定用户名upwd:"" //向双向绑定密码} },methods:{login(){//功能:用户登录任务//1:创建正则表达式验证用户名和密码格式// 规则:字母数字3~12var reg = /^[a-z0-9]{3,12}$/i;//2:获取用户输入用户名var u = this.uname;//3:获取用户输入密码var p = this.upwd;console.log(u+"_"+p);//4:通过正则表达式验证用户名// 如果格式不正确 确认消息 "用户名格式不正确"if(!reg.test(u)){this.$messagebox("消息","用户名格式不正确");return; //返回 }//5:通过正则表达式验证密码 // 如果格式不正确 确认消息 "密码格式不正确"if(!reg.test(p)){this.$messagebox("消息","密码格式不正确");return;}//#6:输出正确 通过ajax请求服务器程序帮助完成登录任务 }}}</script>

②为组件指定访问路径index.js /exam02

src/router/index.js

import Vue from 'vue' //引入Vue对象import VueRouter from 'vue-router' //引入路由//引入自定义组件//1.引入组件exam02.vueimport exam01 from "../components/2.21/exam/exam01.vue"import exam02 from "../components/2.21/exam/exam02.vue"Vue.use(VueRouter)//将路由对象注册V//配置组件-:访问路径const routes = [{path: '/exam01',component: exam01},{path: '/exam02',component: exam02}]//打开浏览器地址:http://127.0.0.1:8080/#/exam02const router = new VueRouter({routes})export default router

③在main.js中引入mint-ui库

main.js

import Vue from 'vue'import App from './App.vue'import router from './router'import store from './store'Vue.config.productionTip = false//功能一:引入和配置mint-ui组件库//1:引入mint-ui所有组件import MintUI from "mint-ui"//2:单独引入mint-ui样式文件import "mint-ui/lib/style.css"//3:将mint-ui对象注册Vue实例Vue.use(MintUI);new Vue({router,//store, //存储对象删除render: h => h(App)}).$mount('#app')

开关组件

标准语法:<mt-switch v-model="val2" @change="handle2">标题内容</mt-switch>

属性:val2: 变量 , 值为boolean (true打开状态 False 关闭状态) , handle2函数写在script >export default>methods:{}里

事件:@change=""修改事件

单选列表

组件:<mt-radio></mt-radio>

属性:title: 标题 ,:options=""列表选项 [{label:value},{}] ,v-model=""绑定变量选中值

表单组件案例

①启动脚手架 , main.js引入mint-ui

②创建组件

src/components/2.21/exam/exam03.vue

<template><div><h3>Exam03.vue</h3><!--第一个组件:开关组件--><mt-switch v-model="val2" @change="handle2">是否接收消息</mt-switch><!--第二个组件:单选列表--><mt-radiotitle="最喜欢的职业选手":options="list"v-model="v3"></mt-radio><mt-button @click="handle3">获取单选列表中选中值</mt-button></div></template><script>export default {data(){return {val2:true, //开关组件状态 true 打开v3:"", //单选列表-->选中值list:[//单选列表{label:"上单",value:"theshy"},{label:"中单",value:"Faker"},{label:"ADC",value:"uzi"}]}//return end},//data endmethods:{handle2(){//功能:获取开关组件状态//this.$messagebox(this.val2);console.log(this.val2)},handle3(){//功能:获取用户选中列表中值this.$toast(this.v3)} }}</script>

③为组件指定路径/exam03

src/router/index.js

import Vue from 'vue'//引入Vue对象import Router from 'vue-router'//引入路由//引入自定义组件//1:引入组件exam03.vueimport exam03 from "../components/2.21/exam/exam03.vue"Vue.use(Router) export default new Router({//export default用于导出模块,在别的模块需要调用这个模块的时候,可以通过import命令引入使用 //配置组件-:访问路径routes: [{path:'/exam03',component:exam03},]})//打浏览器地址 http://127.0.0.1:8080/#/exam03

mint-ui组件库面板底部导航条

Ⅰ 面板语法 :

多个面板显示不同内容同一时刻只能显示一个面板内容

<mt-tab-container v-model="active">面板父元素

<mt-tab-container-item id="tab1">面板一

面板一:

</mt-tab-container-item>

<mt-tab-container-item id="tab2">面板二

面板二:

</mt-tab-container-item>

<mt-tab-container-item id="tab3">面板三

面板三:

</mt-tab-container-item>

</mt-tab-container>

注意 :

面板中id与原生标签id不同,只需保证在当前组件中id不重复即可

变量active 保存某个面板id,则显示某个面板

Ⅱ 底部导航条语法

① / 下载指定图片 (81*81 png)

②创建tabbar 底部导航条

<mt-tabbar v-model=”active”>父元素

<mt-tab-item id=”tab1”>按钮

<img src=”” />按钮中图片

文字按钮中文字

</mt-tab-item>

<mt-tab-item id=”tab2”>按钮

<img src=”” />按钮中图片

文字按钮中文字

</mt-tab-item>

<mt-tab-item id=”tab3”>按钮

<img src=”” />按钮中图片

文字按钮中文字

</mt-tab-item>

</mt-tabbar>

注意 :

当用户点击某个按钮时,将当前按钮id赋值active变量

img 元素添加属性slot="icon"将图片元素添加上方div元素

面板底部导航条案例

示例 :active:"tab1"显示生鲜 ;active:"tab2"显示酒 ;active:"tab3"显示化妆品组件

创建组件exam04.vue

src/components/2.21/exam/exam04.vue

<template><div><h3>Exam04.vue</h3> <!--添加面板组件1:父元素2:生鲜面板 tab13:酒面板tab24:化妆品面板 tab3--><mt-tab-container v-model="active"><mt-tab-container-item id="tab1">生鲜面板</mt-tab-container-item><mt-tab-container-item id="tab2">酒</mt-tab-container-item><mt-tab-container-item id="tab3">化妆品</mt-tab-container-item></mt-tab-container><!--添加底部导航条1:父元素2:一组按钮3:按钮图片 文字--><mt-tabbar v-model="active"> <!--父元素--><mt-tab-item id="tab1"> <!--按钮--><img src="../../../assets/01.png" slot="icon" />生鲜</mt-tab-item><mt-tab-item id="tab2"><img src="../../../assets/02.png" slot="icon"/>酒</mt-tab-item><mt-tab-item id="tab3"><img src="../../../assets/03.png" slot="icon"/>化妆品</mt-tab-item></mt-tabbar></div></template><script>export default {data(){return {//显示指定面板 化妆品active:"tab1"}}}</script>

分配访问路径 /exam04

src/router/index.js

import Vue from 'vue'//引入Vue对象import Router from 'vue-router'//引入路由//引入自定义组件//1:引入组件exam04.vueimport exam04 from "../components/2.21/exam/exam04.vue"Vue.use(Router) export default new Router({//export default用于导出模块,在别的模块需要调用这个模块的时候,可以通过import命令引入使用 //配置组件-:访问路径routes: [{path:'/exam04',component:exam04},]})//打浏览器地址 http://127.0.0.1:8080/#/exam04

① 引入和配置mint-ui组件库

import "./font/iconfont.css"引入图标字体库

main.js

import Vue from 'vue'import App from './App.vue'import router from './router'import store from './store'Vue.config.productionTip = false//功能一:引入和配置mint-ui组件库//1:引入mint-ui所有组件import MintUI from "mint-ui"//2:单独引入mint-ui样式文件import "mint-ui/lib/style.css"//3:将mint-ui对象注册Vue实例Vue.use(MintUI);//功能二:引入图标字体中样式文件,使所有自定义组件均可使用import "./font/iconfont.css"new Vue({router,//store, //存储对象删除render: h => h(App)}).$mount('#app')

组件中数据传递(父组件传递数据子组件) 父组件在模板中调用子组件

父组件:负责创建数据并且传递子组件 , 需要路径

子组件:负责显示数据 , 不要需指定路径

Sub05.vue 子组件负责显示数据

<template><div>{{msg}}</div></template>export default{props:{msg:{default:""}//声明接收父组件数据msg}}

Fa06.vue 父组件创建数据并且传递子组件

(1)引入子组件import Sub05 from "./Sub05.vue"

(2)注册子组件

components:{

Sub05

}

(3) 在模板中调用子组件

<template><sub05 msg="测试数据"></sub05></template>

父组件在模板中调用子组件案例

创建子组件 Sub05.vue , Sub05.vue 子组件负责显示数据,不用指定路径

src/components/2.21/exam/Sub05.vue

<template><div>Sub05.vue<!--1:Sub05.vue 子组件 显示数据--><h1>{{msg}}</h1> </div></template><script>export default {props:{//声明接收父组件数据msg:{default:""}//消息数据}}</script>

创建父组件 Fa06.vue , Fa06.vue 父组件创建数据并且传递子组件

src/components/2.21/exam/Fa06.vue

<template><div><h3>Fa06.vue 父组件</h3><!--3:在模板中调用子组件--><sub05 :msg="msg2"></sub05> </div></template><script>//1:引入指定子组件import Sub05 from "./Sub05.vue"export default {data(){return {msg2:"今天2月10日"}}, //2:注册子组件components:{Sub05} }</script>

src/router/index.js

import Vue from 'vue'//引入Vue对象import Router from 'vue-router'//引入路由//引入自定义组件//1:引入组件exam04.vueimport Sub05 from "../components/2.21/exam/Sub05.vue"import Fa06 from "../components/2.21/exam/Fa06.vue"Vue.use(Router) export default new Router({//export default用于导出模块,在别的模块需要调用这个模块的时候,可以通过import命令引入使用 //配置组件-:访问路径routes: [{path:'/Sub05',component:Sub05},{path:'/Fa06',component:Fa06}]})//打浏览器地址 http://127.0.0.1:8080/#/Fa06

微信消息列表功能案例

第一部分:顶部标题(子组件)

分析功能 :子组件 TitleBar.vue

左侧文字 leftTitle , 右侧两张图片 rightFristImg rightSecondImg

创建子组件 weixin/common/TitleBar.vue , 此组件显示数据

Home.vue 负责创建数据并且调用子组件

子组件负责:显示数据(输出;样式)

父组件负责:创建数据并且传递子组件

目录结构 :

common 文件夹:所有子组件

json 文件夹:模拟数据

Home.vue 父组件 /Home

①src/components/2.21/weixin/common/TitleBar.vue

<template><div class="page-head"><!--左侧文字--><span>{{leftTitle}}</span> <!--右侧两张图片--><div class="right-head"><div class="searchdiv"><img :src="rightFirstImg" style="width:25px;" /></div><div class="searchdiv" style="margin-left:20px;"><img :src="rightSecondImg"style="width:25px;margin-right:15px;"/></div></div></div></template><script>export default {props:{//声明接收父组件数据 //左侧标题leftTitle:{default:""},//右侧图片rightFirstImg:{default:""},rightSecondImg:{default:""}}}</script><style scoped>/*1:外层父元素弹性布局*/.page-head{display: flex;/*指定布局方式:弹性布局*/position: fixed;/*固定定位*/z-index: 999;/*显示元素上方*/width: 100%;/*填满父无素*/justify-content: space-between;/*子元素两端对齐*/align-items: center;/*子元素垂直居中*/ background-color:#3e3a39;padding-left:7px;/*内边距*/padding-right:7px;height:48px;/*元素高度*/color:#fff;font-size:18px;}/*2:右侧元素弹性布局*/.right-head{display: flex;}</style>

②src/components/2.21/weixin/Home.vue

<template><div><div><!--Home.vue--> <!--3:调用顶部标题子组件--><titlebarleftTitle="微信(100)":rightFirstImg="require('../../../assets/ic_search.png')":rightSecondImg="require('../../../assets/ic_add.png')"></titlebar></div></div></template><script>//1:引入顶部标题子组件import TitleBar from "./common/TitleBar.vue"export default {//2:注册顶部标题子组件components:{//指定标签名称:子组件对象"titlebar":TitleBar} }</script>

清空项目页中空白区域

(1)App.vue(根组件) 清除 padding-top:40px;

(2)index.html n.css<link rel="stylesheet"href="n.css” />

③app.vue

<template><div class="app-container"><!--根组件App.vue 显示组件容器--><router-view><!-- 接受router /请求 --></router-view></div></template><style>.app-container{padding-top:0px;padding-bottom:0px;overflow-x:hidden;}.mui-bar-tab .mui-tab-item-tao.mui-active {color: #007aff;}.mui-bar-tab .mui-tab-item-tao {display: table-cell;overflow: hidden;width: 1%;height: 50px;text-align: center;vertical-align: middle;white-space: nowrap;text-overflow: ellipsis;color: #929292;}.mui-bar-tab .mui-tab-item-tao .mui-icon {top: 3px;width: 24px;height: 24px;padding-top: 0;padding-bottom: 0;}.mui-bar-tab .mui-tab-item-tao .mui-icon~.mui-tab-label {font-size:11px;display:block;overflow:hidden;text-overflow:ellipsis;}</style>

④index.html

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1.0"><!-- n.css --><link rel="stylesheet" href="n.css"><title>xz_admin_v2</title></head><body><noscript></noscript><div id="app"></div><!-- built files will be auto injected --></body></html>

第二部分:消息列表(一条消息+多条消息+面板)

创建子组件 common/Message.vue

左侧图片 imgurl

左侧标题 title subtitle

右侧时间 sendtime

⑤src/components/2.21/weixin/common/Message.vue

<template><!--一条消息组件Message.vue--><div class="rootstyle"><!--左侧图片与标题--><div class="leftimgtxt"><img :src="imgurl" class="imgstyle" /><div class="lefttitle"><span class="title">{{title}}</span><span class="subtitle">{{subtitle}}</span></div></div><!--右侧发送时间--><span class="sendtime">{{sendtime}}</span></div></template><script>//接收父组件传递数据 imgurl;title;subtitle;sendtimeexport default {props:{//声明接收父组件传递数据imgurl:{default:""}, //左侧图片 默认值空字符串title:{default:""},//左侧标题默认值空字符串subtitle:{default:""},//左侧子标题 默认值空字符串sendtime:{default:""}//发送时间 默认值空字符串}}</script><style scoped> /*当style标签具有该scoped属性时,其CSS将仅应用于当前组件的元素, 下面的style样式只在上面template这个组件里起作用*//*1:一条消息元素元素*/.rootstyle{display: flex;/*弹性布局*/justify-content: space-between;/*子元素两端对齐*/align-items: center;/*子元素垂直居中*/}/*2:左侧图片与标题父元素*/.leftimgtxt{display: flex;/*子元素水平排列*/}/*3:左侧图片宽度和高度*/.imgstyle{width:50px;/*图片宽度和高度*/height:50px;}/*4:左侧标题与子标题父元素*/.lefttitle{display: flex;/*弹性布局*/flex-direction: column;/*子元素按钮列:排列*/justify-content: center;/*居中对齐*/margin-left:7px;/*标题与左侧图片7像素间距*/ }/*5:左侧标题*/.title{color:#000; /*标题颜色与大小*/font-size:17px;}/*6:左侧子标题*/.subtitle{color:gray;margin-top:4px;/*子标题上面标题间距*/}/*7:右侧发送时间*/.sendtime{color:gray;}</style>

多条消息组件common/MessageList.vue 消息列表 , 引入子组件Message.vue

加载json数据import messagejson from "../json/messagelist.json"import 将json数据->直接->转换js对象

{data:[{}]}—>js对象

data(){

return {rows:messagejson.data}

}

<div>{{rows}}</div>

左侧rows 在data声明变量rows

赋值 rows:messagejson.data 消息列表数组赋值rows

在模板中创建循环显示数组中值

创建循环遍历数据并且传递Message.vue

临时将消息列表组件转全局组件

动态读取图片路径

messagejson.json 01.jpg:imgurl="require(`./../../../../assets/`+item.img)"

⑥src/components/2.21/weixin/common/MessageList.vue

<template><div><!--3:调用子组件 MessageList.vue --><messageclass="itemstyle"v-for="(item,i) of rows":key="i":imgurl="require(`./../../../../assets/`+item.img)":title="item.title":subtitle="item.subtitle":sendtime="item.time"></message></div></template><script>//1:引入子组件import Message from "./Message.vue"//1.1:引入json文件import messagelistjson from "../json/messagelist.json"export default {data(){return {//赋值:将json数组赋值变量rows//messagejson.json{"data":[...]}rows:messagelistjson.data}},created(){console.log(this.rows);}, //2:注册子组件components:{"message":Message //左侧标签名称:组件对象} }</script><style scoped>/*一条消息底部添加一条 灰色下划线 */.itemstyle{padding:5px;border-bottom:1px solid #d9d9d9; }</style>

负责加载模拟数据 json/messagelist.json

查看模拟数据 {“data”:[{},{}]}

src/components/2.21/weixin/json/messagelist.json

{"data":[{"id":1,"img":"01.png","title":"微信支付","subtitle":"获取鼓励通知","time":"16:57"},{"id":2,"img":"02.png","title":"腾讯新闻","subtitle":"白天喝上十杯水才是真正的身体好","time":"16:36"},{"id":2,"img":"a_7.png","title":"腾讯新闻","subtitle":"白天喝上十杯水才是真正的身体好","time":"16:36"} ]}

将消息列表组件完成组装Home.vue , 在Home.vue 创建面板

src/components/2.21/weixin/Home.vue

<template><div><div><!--Home.vue--> <!--1:调用顶部标题子组件--><titlebarleftTitle="微信(100)":rightFirstImg="require('../../../assets/ic_search.png')":rightSecondImg="require('../../../assets/ic_add.png')"></titlebar><!--2:调整布局:保存标题子组件高度--><!--3:消息列表面板--><mt-tab-container v-model="active"> <!--面板父元素--><mt-tab-container-item id="message"> <!--消息列表面板--><messagelist></messagelist></mt-tab-container-item></mt-tab-container><!--4:底部导航条--></div></div></template><script>//1:引入顶部标题子组件import TitleBar from "./common/TitleBar.vue"//1.1:引入消息列表子组件import MessageList from "./common/MessageList.vue"export default {data(){return {active:"message", //默认消息列表组件显示}}, //2:注册顶部标题子组件components:{//指定标签名称:子组件对象"titlebar":TitleBar,"messagelist":MessageList} }</script>

第三部分:底部导航条(tabbar)图片切换+文字颜色

mint-ui 导航条默认图片不能切换

解决方案:创建子组件 功能:显示按钮上方图片并且实现图片切换

common/TabbarIcon.vue

<img :src="focused?selectedImg:normallmage" />

接收三个数据

1.当前按钮是否被选中 focused:true

2.选中图片 selectedImg绿色

3.默认图片 normallmage灰色

⑦src/components/2.21/weixin/common/TabbarIcon.vue

<template><div><!-- 接收几个参数:3个focused选中状态;true falseseletcedImage; 选中图片normalImage 默认图片--><!--h3>common/TabbarIcon.vue</h3--><img :src="focused?selectedImage:normalImage" class="imgstyle"/></div></template><script>export default {props:{//声明接收父组件数据//声明当前元素选中状态focused:false,//选中时显示图片selectedImage:{default:""},//默认时显示图片normalImage:{default:""}}}</script><style scoped>.imgstyle{width:30px;height:30px;}</style>

⑧src/components/2.21/weixin/common/TabBar.vue

<template><div class="page-head"><!--左侧文字--><span>{{leftTitle}}</span> <!--右侧两张图片--><div class="right-head"><div class="searchdiv"><img :src="rightFirstImg" style="width:25px;" /></div><div class="searchdiv" style="margin-left:20px;"><img :src="rightSecondImg"style="width:25px;margin-right:15px;"/></div></div></div></template><script>export default {props:{//声明接收父组件数据 //左侧标题leftTitle:{default:""},//右侧图片rightFirstImg:{default:""},rightSecondImg:{default:""}}}</script><style scoped>/*1:外层父元素弹性布局*/.page-head{display: flex;/*指定布局方式:弹性布局*/position: fixed;/*固定定位*/z-index: 999;/*显示元素上方*/width: 100%;/*填满父无素*/justify-content: space-between;/*子元素两端对齐*/align-items: center;/*子元素垂直居中*/ background-color:#3e3a39;/*16:49*/padding-left:7px;/*内边距*/padding-right:7px;height:48px;/*元素高度*/color:#fff;font-size:18px;}/*2:右侧元素弹性布局*/.right-head{display: flex;}</style>

mint-ui 导航条默认按钮中文字蓝色 实际要求绿色文字

解决办法:覆盖原组件中样式

查找原先组件中样式选择器

默认选中蓝色文字选择器

.mint-tabbar > .mint-tab-item.is-selected{

color:#45c018;

}

默认蓝色文字选择器

.mint-tabbar > .mint-tab-item{

color:#999999;

}

为按钮绑定点击事件 ,完成图片切换

当点选中按钮图片绿,其它图片灰色

为按钮元素绑定点击事件<mt-tab-item>

遇到问题 为按钮绑定点击事件失效

问题原因:<mt-tab-item>按钮组件不支持点击事件

解决思路:添加事件属性nativenative是使用原生组件点击事件

<mt-tab-item @click.native="changeState(0)"></mt-tab-item>

⑨src/components/2.21/weixin/Home.vue

<template><div class="page-tabbar"><div class="page-wrap"><!--Home.vue--> <!--1:调用顶部标题子组件--><titlebarleftTitle="微信(100)":rightFirstImg="require('../../../assets/ic_search.png')":rightSecondImg="require('../../../assets/ic_add.png')"></titlebar><!--2:调整布局:保存标题子组件高度--><div style="margin-top:48px;"></div><!--3:消息列表面板--><mt-tab-container v-model="active"> <!--面板父元素--><mt-tab-container-item id="message"> <!--消息列表面板--><messagelist></messagelist></mt-tab-container-item></mt-tab-container><!--4:底部导航条--><mt-tabbar v-model="active" fixed><!--按钮一:微信 完成三个按钮--><mt-tab-item id="message" @click.native="changeState(0)"><tabbaricon:focused="list[0].isSelect":selectedImage="require('../../../assets/ic_weixin_selected.png')":normalImage="require('../../../assets/ic_weixin_normal.png')"></tabbaricon> 微信</mt-tab-item><!--按钮二:通讯录--><mt-tab-item id="contact" @click.native="changeState(1)"><tabbaricon:focused="list[1].isSelect":selectedImage="require('../../../assets/ic_contacts_selected.png')":normalImage="require('../../../assets/ic_contacts_normal.png')"></tabbaricon> 通讯录</mt-tab-item><!--按钮三:发现--><mt-tab-item id="find" @click.native="changeState(2)"><tabbaricon:focused="list[2].isSelect":selectedImage="require('../../../assets/ic_find_selected.png')":normalImage="require('../../../assets/ic_find_normal.png')"></tabbaricon>发现</mt-tab-item><!--按钮四:我--><mt-tab-item id="me" @click.native="changeState(3)"><tabbaricon:focused="list[3].isSelect":selectedImage="require('../../../assets/ic_me_selected.png')":normalImage="require('../../../assets/ic_me_normal.png')"></tabbaricon>我</mt-tab-item></mt-tabbar></div></div></template><script>//1:引入顶部标题子组件import TitleBar from "./common/TitleBar.vue"//1.1:引入消息列表子组件import MessageList from "./common/MessageList.vue"//1.2:引入底图图片组件import TabBarIcon from "./common/TabbarIcon.vue"export default {data(){return {active:"message", //默认消息列表组件显示list:[{isSelect:true}, //第一个按钮状态 0{isSelect:false}, //第二个按钮状态 1{isSelect:false}, //第三个按钮状态 2{isSelect:false}, //第四个按钮状态 3]}}, methods:{changeState(idx){//功能:完成点击按钮切换图片任务 当前按钮true 其它按钮false///参数idx按钮下标 0 1 2 3//1:创建变量size 表示数组长度var size = this.list.length;//2:创建循环遍历数据list每个元素for(var i=0;i<size;i++){//3:判断如果参数下载idx与当前按钮下标相同if(i==idx){this.list[i].isSelect=true;}else{this.list[i].isSelect=false;}//4:当前元素选中状态true//5:其它元素默认状态false}}}, //2:注册顶部标题子组件components:{//指定标签名称:子组件对象"titlebar":TitleBar, //顶部标题子组件"messagelist":MessageList, //中间消息列表子组件"tabbaricon":TabBarIcon,//底部导航条图片子组件} }</script><style scoped>/*1:最外层父元素*/.page-tabbar{overflow: hidden; /*溢出隐藏*/}/*2:内层元素*/.page-wrap{overflow: auto; /*数据多出现滚动条*/padding-bottom: 60px;/*底部导栏空间*/}/*3:覆盖mint-ui组件原有样式-tabbar按钮中文字选中样式 42*/.mint-tabbar > .mint-tab-item.is-selected{background-color: transparent;color:#45c018;}/*4:覆盖mint-ui组件原有样式-tabbar按钮中文字默认样式*/.mint-tabbar > .mint-tab-item{color:#999999;}</style>

为Home组件指定访问路径

src/router/index.js

import Vue from 'vue'//引入Vue对象import Router from 'vue-router'//引入路由//引入自定义组件//1:引入组件Home.vueimport Home from "../components/2.21/weixin/Home.vue"import MessageList from "../components/2.21/weixin/common/MessageList.vue"Vue.use(Router) export default new Router({//配置组件-:访问路径routes: [{path:'/Home',component:Home}, {path:'/MessageList',component:MessageList}, ]})//打浏览器地址 http://127.0.0.1:8080/#/Home// "/"当前项目 "#"分隔符 "/"路径

用户登录案例

Vue ui 组件库学子商城完成功能:

-用户登录

-商品列表

-将商品添加至购物车

-购物车

学子商城用户登录功能

分析用户登录流程

功能分析

用户打开网页访问登录组件输入用户名和密码格式错误: 3~12位 提示:用户名格式错误

密码格式不错误没有用户输入用户名和密码

提示:用户名和密码不正确用户名和密码正确 跳转商列表组件

分析代码实现(核心内容)

创建一个用户登录数据库表并且保存合法用户名和密码

有一张用户表:xz_user

用户登录表 xz_login 表名id 记录编号 INT PRIMARY KEY AUTO_INCREMENTuname 用户名 VARCHAR(50)upwd 用户密码 VARCHAR(32)

密码数据特殊,此数据需要加密后才能保存数据库中 加密密码原因是:防止内部工作人员泄密

加密密码方式mysql有一个函数md5() 加密函数

md5 单向加密算法

使用: md5(‘123’)

SELECT md5(“123”) => “2389dsuisd7832iuwe89w23e98” 32位

高级别安全建议

(1)多次循环加密 md5(md5(‘123’))

(2)加强密码规则[最有效]

8位以上:小写大写字母数字特殊符号 示例:1_bC_-!00A

参与完成此功能所有程序

-数据库表 xz_login

-node 服务器程序 app.js

-Login.vue 脚手架创建组件

服务器端目录结构

vue_app_00_null 脚手架下载保存所在文件命名为

vue_server_00 服务器程序 脚手架 服务器程序是分开放的 放一起就都不能用

vue_server_00/

public 静态资源(图片;视频;音频;…)

app.js 服务器程序

db.sql 所有sql语法

node_modules #第三方模块此目录和脚手架node_modules完全不同

安装xampp 软件

xampp软件包(mysql;php;apache;…)

官网 : windows /index.html mac /projects/xampp/files/

安装nodejs 软件

node.js 淘宝镜像/mirrors/node/ /dist/v9.10.0/

windows

node-v9.10.0-x64.msi #64系统

node-v9.10.0-x86.msi #32 系统mac

node-v9.10.0.pkg #mac系统

注意版本 #8.10 最低要求

>node -v

v8.11.4

创建服务器目录下载安装第三方模块

express web服务器

express-session session对象

mysql mysql驱动程序

cors 跨域模块

express-session

mysql 配置连接池

var pool = mysql.createPool({

host:”127.0.0.1”,

user:”root”,

password:””,

database:”xz”,

port:3306

})cors 跨域

脚手架8080 node服务器(安装跨域模块) 4000

以上脚手架发送请求给node服务器出错(跨域)

解决方式 : 跨域模块 跨域模块在服务器端运行:(允许跨域访问脚手架)列表

cors({

origin:[“http://127.0.0.1:8080”,”http://localhost:8080”] //允许跨域访问脚手架

})

app.js功能一 : 用户登录验证(用户登录服务器端(node))
node描述功能:

(1)获取脚手架提供用户名和密码

(2)将用户名和密码拼接sql语句查询是否有匹配合法记录

(3)将结果返回脚手架 登录成功 登录失败获取脚手架提供用户名和密码

GET /login?uname=tom&upwd=123

var u = req.query.uname; 接收脚手架用户名

var p = req.query.upwd 接收脚手架用户密码将用户名和密码拼接sql语句查询是否有匹配合法记录

#通用套路 查询;查找;搜索;获取… SELECT

SELECT id FROM xz_login WHERE uname=? AND upwd=md5(?)将结果返回脚手架 登录成功 登录失败

pool.query(sql,[uname,upwd],(err,result)=>{

if(err) throw err; #程序出现严重错,停止执行抛出错误对象

result 查询sql结果数组

result.length==0 查询失败 用户名或密码错

result.length!=0 查询成功 登录成功

});

res.send({code:1,msg:“登录成功”})

res.send({code:-1,msg:“用户名或密码有误”})

db.sql

#功能一:完成用户登录表创建CREATE DATABASE xz;#1:进入xz库USE xz;#2:创建xz_login表CREATE TABLE xz_login(id INT PRIMARY KEY AUTO_INCREMENT,uname VARCHAR(50),upwd VARCHAR(32));#3:添加二条测试数据[合法]INSERT INTO xz_login VALUES(null,'tom',md5('123'));INSERT INTO xz_login VALUES(null,'jerry',md5('123'));

准备工作① : 启动数据库,复制上面创建数据库粘贴进来

准备工作② : 启动服务器 vscode中右键app.js文件打开终端输入node app.js回车

app.js

//功能:服务器程序//1:引入四个模块const express = require("express"); //web服务器模块const mysql = require("mysql");//mysql模块const session = require("express-session");//session模块const cors = require("cors");//跨域//2:创建连接池var pool = mysql.createPool({host:"127.0.0.1",user:"root",password:"",database:"xz",port:3306,connectionLimit:15})//3:创建web服务器var server = express();//4:配置跨域模块//4.1:允许程序列表 脚手架//4.2:每次请求验证server.use(cors({origin:["http://127.0.0.1:8080","http://localhost:8080"],credentials:true }))//5:指定静态资源目录 publicserver.use(express.static("public"));//6:配置session对象 !!!//7:为服务器绑定监听端口 4000server.listen(4000);console.log("服务器起动.......");//功能一:用户登录验证server.get("/login",(req,res)=>{//1:获取脚手架传递用户名和密码var u = req.query.uname;var p = req.query.upwd;//2:创建sql语法并且将用户名和密码加入var sql = "SELECT id FROM xz_login WHERE uname=? AND upwd=md5(?)";//3:执行sql语法并且获取返回结果pool.query(sql,[u,p],(err,result)=>{//3.1:如果出现严重错误抛出 if(err)throw err;if(result.length==0){res.send({code:-1,msg:"用户名或密码有误"});}else{//res.send({code:1,msg:"登录成功"})}});})//测试:你 //启动服务器 node app.js//打开浏览器在地址栏输入//http://127.0.0.1:4000/login?uname=tom&upwd=123 如果出现错误,检查数据库重新开启,开启后node也需要重新开启 错误二:服务器错误 node已开启重复开占端口需要关闭//http://127.0.0.1:4000/login?uname=tom&upwd=122

准备工作③ : 打开浏览器在地址栏输入 http://127.0.0.1:4000/login?uname=tom&upwd=123

无法访问服务器错误一

错误一: 检查数据库3306是否开启,开启后node也需要重新开启

错误二: 服务器错误 node已开启重复开占端口需要关闭,如果报错服务器错误,如下图显示4000端口占用说明重复开启服务器会导致地址栏获取不到数据报服务器错误,点击图示删除按钮重新node app.js开启

脚手架概念

脚手架是一个工具叫做 vue-cli 只需要全局安装一次

vue-cli 生成一个脚手架项目 vue_app_00_null(上面案例脚手架文件名) 本机有node即可使用

vue_app_00_null 使用项目

案例的脚手架文件 Login.vue

创建组件vue_app_00_null/src/components/2.21/xz/Login.vue 指定路径 /login

添加二个输入框 , 一个登录按钮

vue_app_00_null/src/components/2.21/xz/Login.vue

<template><div><h3>Login.vue</h3><!--添加二个输入框 用户名和密码--><mt-field placeholder="请输入用户名" v-model="uname"></mt-field><mt-field placeholder="请输入密码" v-model="upwd"></mt-field><!--添加一个登录按钮--><mt-button size="large" @click="login">登录</mt-button></div></template><script>export default {data(){return {uname:"tom",upwd:"123"}},methods:{login(){//功能:完成用户登录 //1:创建正则表达式用于验证用户名和密码// 字母和数字 3~12var reg = /^[a-z0-9]{3,12}$/i;//2:获取用户名和密码var u = this.uname;var p = this.upwd;console.log(u+"_"+p);//3:验证用户名如果格式不正确,提示错误信息if(!reg.test(u)){this.$messagebox("消息","用户名格式不正确");return;//停止程序运行}//4:验证用户密码如果格式不正确,提示错误信息if(!reg.test(p)){this.$messagebox("消息","密码格式不正确");return;//停止程序运行 }//console.log(3);//5:创建url变量,保存请求服务器地址var url = "login";//6:创建obj变量,保存请求时参数var obj = {uname:u,upwd:p};//7:发送ajax请求this.axios.get(url,{params:obj}).then(res=>{//8:接收服务器返回结果//9:如果-1 提示用户名和密码有误//10:如果1 跳转商品列表组件 /Product if(res.data.code==-1){this.$messagebox("消息","用户名或密码有误");}else{this.$toast("登录成功");this.$router.push("/Product");}})}}}</script>

ue_app_00_null/src/router/index.js

import Vue from 'vue'//引入Vue对象import Router from 'vue-router'//引入路由//引入自定义组件//1:引入组件Login.vueimport Login from "../components/2.21/xz/Login.vue"Vue.use(Router)export default new Router({//配置组件-:访问路径routes: [{path:'/Login',component:Login}]})

发送ajax请求 [脚手架8080–>服务器4000]

解决问题使用ajax模块

ajax解决方式 : 原生ajax , jquery , axios(vue ajax模块) , request

安装使用axios

①下载第三方ajax模块 脚手架文件夹下打开cmd 输入指令npm i axios安装

vue_app_00_null/npm i axios

②在main.js 全局配置 [所有组件均可以使用axios] :

将模块引入当前项目中import axios from "axios"配置访问服务器基础地址axios.defaults.baseURL = "http://127.0.0.1:4000/";发送请求保存session信息axios.defaults.withCredentials=true将axios对象注册VueVue.prototype.axios = axios;

示例:请求用户登录程序this.axios.get("login");baseURL会把ttp://127.0.0.1:4000/放到前面 , this.axios.get(“http://127.0.0.1:4000/login”);

vue_app_00_null/src/main.js

import Vue from 'vue' //vue实例对象import App from './App.vue' //根组件import router from './router'//路由模块//选择代码 main.js 5~75 删除 删除!!!//选择一行代码删除 //功能一:引入和配置mint-ui组件库//1:引入mint-ui所有组件import MintUI from "mint-ui"//2:单独引入mint-ui样式文件import "mint-ui/lib/style.css"//3:将mint-ui对象注册Vue实例 34Vue.use(MintUI);//功能二:引入图标字体中样式文件,使所有自定义组件均可使用import "./font/iconfont.css"//功能三:引入axios库//1:引入axios库import axios from "axios"//2:配置访问服务器基础路径axios.defaults.baseURL="http://127.0.0.1:4000/"//3:配置保存session数据axios.defaults.withCredentials=true//4:注册Vue.prototype.axios = axios;//以下代码一定在main.js最后new Vue({router, //路由对象render: h => h(App),}).$mount('#app')

session对象
session对象 是保存在服务器端的对象,保存的数据 : 用户登录凭证 用户权限session对象生命周期

创建用户打开浏览器访问服务器时:session对象创建-----开始

中间用户可以通过浏览器访问服务器多个程序:session-----使用中

当用户关闭浏览器session对象销毁或者服务器程序停止工作 session对象销毁session对象下载配置和使用

session对象下载第三方模块 在服务器端程序下载模块express-sessionnpm i express-session

app.js 服务器端配置session对象server.use(session({}))有三个配置项 :

secret: 安全字符串session对象加密数据使

resave:true每次请求更新服务器数据

saveUninitialized保存初始化数据

如何在服务器端使用

①用户登录成功后将登录凭证保存session对象中

req.session.uid = 1; //将用户登录id作为凭证保存session对象中

②当用户访问商品列表时获取session对象中uid

var uid = req.session.uid; //获取uid

if(!uid){ //判断

res.send({code:-2,msg:“请求登录”});return;

}

app.js 功能一 – 功能三

服务器vue_server_00/app.js

//功能:服务器程序//1:引入四个模块const express = require("express"); //web服务器模块const mysql = require("mysql");//mysql模块const session = require("express-session");//session模块const cors = require("cors");//跨域//2:创建连接池var pool = mysql.createPool({host:"127.0.0.1",user:"root",password:"",database:"xz",port:3306,connectionLimit:15})//3:创建web服务器var server = express();//4:配置跨域模块//4.1:允许程序列表 脚手架//4.2:每次请求验证server.use(cors({origin:["http://127.0.0.1:8080","http://localhost:8080"],credentials:true }))//5:指定静态资源目录 publicserver.use(express.static("public"));//6:配置session对象server.use(session({secret:"128位安全字符串",//加密条件resave:true,//每次请求更新数据saveUninitialized:true,//保存初始化数据}));//7:为服务器绑定监听端口 4000server.listen(4000);console.log("服务器起动.......");//功能一:用户登录验证server.get("/login",(req,res)=>{//1:获取脚手架传递用户名和密码var u = req.query.uname;var p = req.query.upwd;//2:创建sql语法并且将用户名和密码加入var sql = "SELECT id FROM xz_login WHERE uname=? AND upwd=md5(?)";//3:执行sql语法并且获取返回结果pool.query(sql,[u,p],(err,result)=>{//3.1:如果出现严重错误抛出 if(err)throw err;//3.2:如果result.length长度为0,表示登录失败if(result.length==0){res.send({code:-1,msg:"用户名或密码有误"});}else{//登录成功//如果用户登录成功:创建session对象并且将登录凭证uid//保存对象中 result=[{id:1}]//将当前登录用户id保存session对象中作业:登录凭证req.session.uid = result[0].id;res.send({code:1,msg:"登录成功"})}});})//测试:你 //启动服务器 node app.js//打开浏览器在地址栏输入//http://127.0.0.1:4000/login?uname=tom&upwd=123//http://127.0.0.1:4000/login?uname=tom&upwd=122//功能二:显示商品列表-(分页)//1:GET /product server.get("/product",(req,res)=>{//2:接收参数 页码 一页几行var pno = req.query.pno;var ps = req.query.pageSize;//3:为参数设置默认值 1 20if(!pno){pno=1}if(!ps){ps=20}//4:创建sql语句分页查询商品列表var sql = "SELECT lid,lname,price,pic FROM xz_laptop LIMIT ?,?";var offset = (pno-1)*ps;ps = parseInt(ps);//5:执行sql语句并且将结果发送脚手架pool.query(sql,[offset,ps],(err,result)=>{if(err)throw err;res.send({code:1,msg:"查询成功",data:result})})})//测试// 1:启动node app.js// 2:http://127.0.0.1:4000/product// 3:http://127.0.0.1:4000/product?pno=2// 4:http://127.0.0.1:4000/01.jpg// 5:http://127.0.0.1:4000/02.jpg//功能三:将商品添加至购物车server.get("/addcart",(req,res)=>{//1:获取当前登录用户凭证var uid = req.session.uid;//2:如果当前用户没有登录凭证 输出请登录if(!uid){res.send({code:-2,msg:"请登录"});return;}//3:获取脚手架传递数据 lid,lname,pricevar lid = req.query.lid;var lname = req.query.lname;var price = req.query.price;//4:创建sql语句 查询当前用户是否购买过此商品var sql = "SELECT id FROM xz_cart WHERE uid=? AND lid=?";//5:执行sql语句pool.query(sql,[uid,lid],(err,result)=>{//6:在回调函数(钩子函数)if(err)throw err;//7:获取查询结果[判断是否购买过此商品]if(result.length==0){//8:如果没买过此商品 创建INSERT SQLvar sql = `INSERT INTO xz_cart VALUES(null,${lid},'${lname}',${price},1,${uid})`;}else{//9:如果己购买过此商品 创建UPDATE SQLvar sql = `UPDATE xz_cart SET count=count+1 WHERE uid=${uid} AND lid=${lid}`;}//10:执行sql//11:返回结果脚手架pool.query(sql,(err,result)=>{if(err)throw err;res.send({code:1,msg:"添加成功"})})})//select end//测试//1:下载 db02.sql 复制代码 mysql执行//2:启动node node app.js//3:浏览器地址// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa// http://127.0.0.1:4000/login?uname=tom&upwd=123 //登录 浏览器不能关// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa //添加// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa //再试一次添加// SELECT * FROM xz_cart; //查询数据库 空xz_cart添加一条数据})

无法访问服务器错误二

下面 商品列表 > 服务器程序 > 数据库 node 栏目将介绍 上述代码中功能二:显示商品列表-(分页) , 功能三:将商品添加至购物车 原理

vscode中右键app.js文件打开终端输入node app.js开启服务器 , 浏览器地址栏输入上面(app.js)代码测试中的地址, 如报错可查看vscode终端 ,注意数据库中列表表头名是否写错或者图片是否引入(商品列表 > 服务器程序 > 数据库 ⑤中)

商品列表

商城网站图片保存在服务器端 public

服务器程序

数据库

①商品表 xz_laptop 添加一列 pic 保存商品指定图片

②更新xz_laptop eg: lid=1 01.jpg , lid>1 02.jpg

③截取两张图片 01.jpg ,02.jpg , 将图片保存服务器端public目录下 即vue_server_00/public

如果xz_laptop 表不存在需要导入此表

数据库中导入表格 ①#mysql -uroot -p > 拖动xz.sql 命令窗口按回车

②#mysql -uroot -p > use xz;>复制xz.sql内容 shell中右键(粘贴) ,如下

vue_server_00/db01.sql

#db01.sql#功能二:商品列表 #1:向xz_laptop 商品列表中添加一列pic保存商品图片USE xz;ALTER TABLE xz_laptop ADD pic VARCHAR(255);#2:更新pic列数据UPDATE xz_laptop SET pic='01.jpg' WHERE lid = 1;UPDATE xz_laptop SET pic='02.jpg' WHERE lid > 1;#3:复制mysql控制台执行生效(你操作)

启动XAMPP,见端口号3306即为正常工作, 打开shell 输入mysql -uroot -p开启数据库,复制上面db01.sql指令,粘贴到MariaDB [(none)]> 后 , 本例两张图片即存进了数据库

未调图片进数据库报的错(vscode /node app.js) , 解决: shell中use xz;粘贴 db01.sql里的指令进来

app.js功能二 : 显示商品列表-(分页)

node app.js功能二

请求方式 GET 请求地址 /product

参数 页码2 pno 一页几行 20 pageSize

sql

SELECT lid,lname,price,pic FROM xz_laptop

LIMIT ?,?

? 起始行数 (算法公式:var offset =(pno-1)*pageSize;页码减1乘以页大小(页大小:一页有几行))

? 一页显示几行 pageSize

-将数据组装什么样式格式返回脚手架

res.send({code:1,msg:“查询成功”,data:result})

脚手架

创建组件 xz/Product.vue 分配访问路径 /Product

设计组件

组件创建成功显示第一页数据

created(){} 当组件创建成功后立即调用此函数(创建 生命周期)

loadMore(){} 发送ajax请求获取商品列表

点击按钮显示下一页数据

方法一 : 点击加载更多按钮完成此操作-vue ui

<mt-button @click="loadMore">加载更多</mt-button>

方法二 : 向上滑动完成下一页加载操作-小程序

准备工作④ : vscode中右键package.json打开终端 npm run serve

vue_app_00_null/src/components/2.21/xz/Product.vue

<template><!--弹性布局:外层元素--><div class="product_app"><!--一个商品--><div class="goods-item" v-for="(item,i) of list" :key="i"><!--商品图片--><img :src="'http://127.0.0.1:4000/'+item.pic" /><!--商品名称--><h4>{{item.lname}}</h4><!--商品价格--><h5>{{item.price}}</h5><!--加入购物车按钮--><mt-button>加入购物车</mt-button></div> <!--查看购物车按钮--><mt-button size="large">查看购物车</mt-button><!--加载更多按钮--><mt-button size="large" @click="loadMore">加载更多</mt-button></div></template><script>export default {data(){return {list:[],//商品列表pno:0, //页码1 2 3 .. }},created(){//组件创建成功this.loadMore(); //加载数据},methods:{loadMore(){//console.log(123); //功能:发送ajax请求获取服务器返回商品列表//并且把数据保存data list:[]//node GET /product pno pageSize//1:创建变量url保存请求地址48var url = "product";//1.1:修改页码值加1this.pno++;//2:创建变量obj 请求服务器参数var obj = {pno:this.pno,pageSize:20}//3:发送ajax请求this.axios.get(url,{params:obj}).then(res=>{//4:获取服务器端返回商品列表数据//console.log(res.data);//5:在data添加属性list:[] 保存商品列表//this.list = res.data.data;//多页数据追加操作var rows = this.list.concat(res.data.data);this.list = rows;//6:将返回数据保存list结束})} }}</script><style scoped>/*1:最外层父元素弹性布局*/.product_app{display: flex;/*弹性布局*/flex-wrap:wrap;/*子元素换行*/justify-content: space-between;/*子元素两端对齐*/padding:4px;/*内边距*/ }/*2:一个商品*/.goods-item{width:48%;/*占用屏幕一半*/border:1px solid #ccc;/*边框*/border-radius:5px;/*圆角*/margin:2px 0;/*外边距*/padding:2px;display:flex; /*子元素设置弹性布局*/flex-direction: column;/*按列排放*/min-height:275px; }/*3:一张图片 */.goods-item img{width:100%;}</style>

npm run serve报错

解决方法 : 下载第三方ajax模块 脚手架文件夹下打开cmd 输入指令npm i axios安装 , vue_app_00_null/ npm i axios (参见 “发送ajax请求 [脚手架8080–>服务器4000]” 栏目)

vue_app_00_null/src/router/index.js

import Vue from 'vue'//引入Vue对象import Router from 'vue-router'//引入路由//引入自定义组件//1:引入组件Login.vueimport Login from "../components/2.21/xz/Login.vue"import Product from "../components/2.21/xz/Product.vue"Vue.use(Router)export default new Router({//配置组件-:访问路径routes: [{path:'/Login',component:Login},{path:'/Product',component:Product}]})

将商品添加至购物车功能

功能分析 : 用户将商品添加至购物车 , 购物车数据可以保存在哪里?

-客户端浏览器cookie 京东

-服务器端数据库 xz_cart(此次方案)

-服务器端文件(读取慢 不可取) cart.txt

node.js 程序(异步执行)

数据库表

xz_cart [id;lid;price;lname;count;uid];

id 数据编号

lid 产品编号

price 价格

lname 商品名称

count 购物此商品数量

uid 谁买的 uid

app.js功能三 : 将商品添加至购物车

中间人程序 app.js功能三

GET /addcart lid,price,lname

xz_cart[id;lid,;lname;price;count,uid]

sql 语法:

#查询当前用户是否购买过此商品(没买过添加,买过更新)

SELECT id FROM xz_cart WHERE uid=? AND lid=?

#将用户喜欢商品添加至购物车表

INSERT INTO xz_cart VALUES(null,?,?,?,1,?);

#更新购物车中某件商品数量

UPDATE xz_cart SET count=count+1 WHERE id=? AND uid=?

遇到问题 : 以上操作会触发node异步工作方法(无序), 由于无序结果一定错!

解决问题 :

(1)回调函数then[钩子函数] --简单

(2)Promise 对象

vue_server_00/db02.sql

#功能三:创建购物车表USE xz;CREATE TABLE xz_cart(id INT PRIMARY KEY AUTO_INCREMENT,lid INT,lname VARCHAR(255),price DECIMAL(10,2),count INT,uid INT);

全选复制db02.sql指令 , 打开XAMPP shell

node app.js 重启服务器 , 要删除之前开过的 避免4000端口占用

app.js 中打开浏览器报错

数据库问题 : 原因:登录验证表(xz_login)不存在 , 购物车表(xz_cart)没有引入 , 商品列表(xz_laptop)不存在

XAMPP打开 Apache 然后点击MySQL的Admin按钮查看数据库是否存在 , 不存在则添加

脚手架操作流程

为(加入购物车)按钮绑定点击事件

<mt-button @click="addcart">加入购物车</mt-button>

获取当前商品三个数据 lname;lid;price

<mt-button @click="addcart(item.lname,item.lid,item.price)">加入购物车</mt-button>

发送ajax请求完成添加购物车操作

addcart(lname,lid,price){

var url = “addcart”;

var obj={lname,lid,price};

this.axios.get(url,{params:obj}).then(res=>{

})

}

服务器返回信息 {code:-2,msg:“未登录”} 跳转登录组件

this.$ router.push("/Login");

服务器返回信息 {code:1,msg:“添加成功”} 显示提示短消息

this.$toast(“添加成功”)

脚手架 添加购物车组件Product.vue

vue_app_00_null/src/components/2.21/xz/Product.vue

<template><!--弹性布局:外层元素--><div class="product_app"><!--一个商品--><div class="goods-item" v-for="(item,i) of list" :key="i"><!--商品图片--><img :src="'http://127.0.0.1:4000/'+item.pic" /><!--商品名称--><h4>{{item.lname}}</h4><!--商品价格--><h5>{{item.price}}</h5><!--加入购物车按钮--><mt-button@click="addcart(item.lid,item.lname,item.price)">加入购物车</mt-button></div> <!--查看购物车按钮--><mt-button size="large" @click="findCart">查看购物车</mt-button><!--加载更多按钮--><mt-button size="large" @click="loadMore">加载更多</mt-button></div></template><script>export default {data(){return {list:[],//商品列表pno:0, //页码1 2 3 .. }},created(){//组件创建成功this.loadMore(); //加载数据},methods:{findCart(){this.$router.push("/Cart");},addcart(lid,lname,price){console.log(1);console.log(lid+"_"+lname+"_"+price); //功能:将商品信息添加至购物车 完成任务//1:创建变量url保存请求服务器地址var url="addcart";//2:创建变量obj请求时数据 lid,lname,pricevar obj = {lid,lname,price};//3:发送ajax请求this.axios.get(url,{params:obj}).then(res=>{//4:接收服务器返回数据if(res.data.code==-2){//5:判断code==-2 提示请登录 跳转 /Login组件this.$toast("请登录");this.$router.push("/Login");}else{this.$toast("添加成功") //6:判断code==1 提示添加成功 }}) },loadMore(){//console.log(123); //功能:发送ajax请求获取服务器返回商品列表//并且把数据保存data list:[]//node GET /product pno pageSize//1:创建变量url保存请求地址48var url = "product";//1.1:修改页码值加1this.pno++;//2:创建变量obj 请求服务器参数var obj = {pno:this.pno,pageSize:20}//3:发送ajax请求this.axios.get(url,{params:obj}).then(res=>{//4:获取服务器端返回商品列表数据//console.log(res.data);//5:在data添加属性list:[] 保存商品列表//this.list = res.data.data;//多页数据追加操作var rows = this.list.concat(res.data.data);this.list = rows;//6:将返回数据保存list结束})} }}</script><style scoped>/*1:最外层父元素弹性布局*/.product_app{display: flex;/*弹性布局*/flex-wrap:wrap;/*子元素换行*/justify-content: space-between;/*子元素两端对齐*/padding:4px;/*内边距*/ }/*2:一个商品*/.goods-item{width:48%;/*占用屏幕一半*/border:1px solid #ccc;/*边框*/border-radius:5px;/*圆角*/margin:2px 0;/*外边距*/padding:2px;display:flex; /*子元素设置弹性布局*/flex-direction: column;/*按列排放*/min-height:275px; }/*3:一张图片 */.goods-item img{width:100%;}</style>

完成上面代码后, 检查数据库服务器是否开启正常,然后开启脚手架,打开浏览器查看

常见错误一

登录不成功 Login.vue tom/123

①正则表达式 ②脚手架没写完:登录成功跳转商品列表组件

Network error

如何解决:仔细查询app.js 服务器控制台错误信息

①数据库没有启动 错误码Error: connect ECONNREFUSED 127.0.0.1:3306mysql没启动

②表不存在

③sql语句写错了

④参数中数据不正确 undefined ;; lid/lname/price

错误码ER_BAD_FIELD_ERROR: Unknown column 'undefined' in 'field list'

app.js功能四 : 查询(指定用户)购物车列表

上图 : req.session.uid=1登录凭证 用户的uid1脚手架组件发送给中间人node服务器2查数据库3返回4数据显示到脚手架组件中

代码实现 :

数据库中的表 (购物车) xz_cart xz_cart(id;lid;price;lname,count,uid)

中间人 app.js 👇

前置条件:用户必须登录成功后才能查询购物车信息判断登录凭证 req.session.uid创建sql 语句(服务器端代码)

SELECT id,lid,lname,price,count FROM xz_cart WHERE uid = ?将查询结果返回脚手架

res.send({code:1,msg:“查询成功”,data:result})

脚手架组件 (购物车) Cart.vue

app.js 功能一 – 功能五

vue_server_00/app.js

//功能:服务器程序//1:引入四个模块const express = require("express"); //web服务器模块const mysql = require("mysql");//mysql模块const session = require("express-session");//session模块const cors = require("cors");//跨域//2:创建连接池var pool = mysql.createPool({host:"127.0.0.1",user:"root",password:"",database:"xz",port:3306,connectionLimit:15})//3:创建web服务器var server = express();//4:配置跨域模块//4.1:允许程序列表 脚手架//4.2:每次请求验证server.use(cors({origin:["http://127.0.0.1:8080","http://localhost:8080"],credentials:true }))//5:指定静态资源目录 publicserver.use(express.static("public"));//6:配置session对象server.use(session({secret:"128位安全字符串",//加密条件resave:true,//每次请求更新数据saveUninitialized:true,//保存初始化数据}));//7:为服务器绑定监听端口 4000server.listen(4000);console.log("服务器起动.......");//功能一:用户登录验证server.get("/login",(req,res)=>{//1:获取脚手架传递用户名和密码var u = req.query.uname;var p = req.query.upwd;//2:创建sql语法并且将用户名和密码加入var sql = "SELECT id FROM xz_login WHERE uname=? AND upwd=md5(?)";//3:执行sql语法并且获取返回结果pool.query(sql,[u,p],(err,result)=>{//3.1:如果出现严重错误抛出 if(err)throw err;//3.2:如果result.length长度为0,表示登录失败if(result.length==0){res.send({code:-1,msg:"用户名或密码有误"});}else{//登录成功//如果用户登录成功:创建session对象并且将登录凭证uid//保存对象中 result=[{id:1}]//将当前登录用户id保存session对象中作业:登录凭证req.session.uid = result[0].id;res.send({code:1,msg:"登录成功"})}});})//测试:你 //启动服务器 node app.js//打开浏览器在地址栏输入//http://127.0.0.1:4000/login?uname=tom&upwd=123//http://127.0.0.1:4000/login?uname=tom&upwd=122//功能二:显示商品列表-(分页)//1:GET /product server.get("/product",(req,res)=>{//2:接收参数 页码 一页几行var pno = req.query.pno;var ps = req.query.pageSize;//3:为参数设置默认值 1 20if(!pno){pno=1}if(!ps){ps=20}//4:创建sql语句分页查询商品列表var sql = "SELECT lid,lname,price,pic FROM xz_laptop LIMIT ?,?";var offset = (pno-1)*ps;ps = parseInt(ps);//5:执行sql语句并且将结果发送脚手架pool.query(sql,[offset,ps],(err,result)=>{if(err)throw err;res.send({code:1,msg:"查询成功",data:result})})})//测试// 1:启动node app.js// 2:http://127.0.0.1:4000/product// 3:http://127.0.0.1:4000/product?pno=2// 4:http://127.0.0.1:4000/01.jpg// 5:http://127.0.0.1:4000/02.jpg//功能三:将商品添加至购物车server.get("/addcart",(req,res)=>{//1:获取当前登录用户凭证var uid = req.session.uid;//2:如果当前用户没有登录凭证 输出请登录if(!uid){res.send({code:-2,msg:"请登录"});return;}//3:获取脚手架传递数据 lid,lname,pricevar lid = req.query.lid;var lname = req.query.lname;var price = req.query.price;//4:创建sql语句 查询当前用户是否购买过此商品var sql = "SELECT id FROM xz_cart WHERE uid=? AND lid=?";//5:执行sql语句pool.query(sql,[uid,lid],(err,result)=>{//6:在回调函数(钩子函数)if(err)throw err;//7:获取查询结果[判断是否购买过此商品]if(result.length==0){//8:如果没买过此商品 创建INSERT SQLvar sql = `INSERT INTO xz_cart VALUES(null,${lid},'${lname}',${price},1,${uid})`;}else{//9:如果己购买过此商品 创建UPDATE SQLvar sql = `UPDATE xz_cart SET count=count+1 WHERE uid=${uid} AND lid=${lid}`;}//10:执行sql//11:返回结果脚手架pool.query(sql,(err,result)=>{if(err)throw err;res.send({code:1,msg:"添加成功"})})})//select end//测试// 1:启动 xmapp 启动mysql // USE xz;// SELECT * FROM xz_cart;// 下载昨天db02.sql 执行//2:启动node node app.js//3:浏览器地址// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa// http://127.0.0.1:4000/login?uname=tom&upwd=123// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa// SELECT * FROM xz_cart;})//功能四:查询指定用户购物车列表server.get("/findcart",(req,res)=>{//1:获取用户登录凭证uidvar uid = req.session.uid;//2:没有uid表示此用户未登录 发送请登录信息if(!uid){res.send({code:-2,msg:"请登录",data:[]});return;}//3:创建sql语句var sql = "SELECT id,lid,lname,price,count FROM xz_cart WHERE uid=?";//4:发送sql语句并且将查询结果返回脚手架pool.query(sql,[uid],(err,result)=>{if(err)throw err;res.send({code:1,msg:"查询成功",data:result});})});//测试// 重新启动node node app.js// 打开浏览器在地址栏 // http://127.0.0.1:4000/findcart #请登录// http://127.0.0.1:4000/login?uname=tom&upwd=123 // http://127.0.0.1:4000/findcart #查询结果// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa// http://127.0.0.1:4000/addcart?lid=2&price=9&lname=aa// http://127.0.0.1:4000/findcart #查询结果//功能五:删除购物车中一条商品信息server.get("/del",(req,res)=>{//1:获取用户登录凭证var uid = req.session.uid;//2:如果没有登录凭证 请登录if(!uid){res.send({code:-2,msg:"请登录"});return;}//3:获取脚手架传递数据 idvar id = req.query.id;//4:创建sql依据id删除数据var sql = "DELETE FROM xz_cart WHERE id = ? AND uid=?";//5:执行sql语句获取返回结果pool.query(sql,[id,uid],(err,result)=>{if(err)throw err;//判断删除是否成功 affectedRows 影响行数if(result.affectedRows>0){res.send({code:1,msg:"删除成功"});}else{res.send({code:-1,msg:"删除失败"});}});//6:将结果返回脚手架})//测试// 1: 重新启动 node app.js // select * from xz_cart;// 2: 打开浏览器测 http://127.0.0.1:4000/del?id=1// 3: 打开浏览器测 http://127.0.0.1:4000/login?uname=tom&upwd=123// 4: 打开浏览器测 http://127.0.0.1:4000/del?id=1// 5: 打开浏览器测 http://127.0.0.1:4000/del?id=1

脚手架 购物车组件Cart.vue

vue_app_00_null/src/components/2.21/xz/Cart.vue

<template><div><!--h3>Cart.vue 购物车</h3--><!--(1)顶部全选复选框--><div class="selectall">全选<input type="checkbox" v-model="isAgree"/></div><!--(2)购物车商品列表 --><div class="cartItem" v-for="(item,i) of list" :key="i"><div class="leftImgTxt"><input type="checkbox" :checked="isAgree"/><div class="title">{{item.lname}}</div><div class="title">{{item.price}}</div></div><mt-button @click="del(item.id)">删</mt-button></div><!--(3)一组按钮--><div>购物车中商品数量<span style="color:red">3</span><mt-button>删除选中商品</mt-button><mt-button>清空购物车</mt-button></div></div></template><script>export default {data(){return {list:[], //购物车购物信息isAgree:false, //全选按钮状态}},created(){//组件创建成功后获取购物车列表信息this.loadMore(); },methods:{del(id){//功能:删除购物车中指定商品console.log(id);//1:显示交互对话框this.$messagebox.confirm("是否删除指定商品?").then(res=>{//用户点击确认按钮//2:如果有户选中 确认//3:创建变量url 保存中间人删除程序地直 /delvar url = "del";//4:创建变量obj 保存idvar obj = {id}//5:发送ajax请求this.axios.get(url,{params:obj}).then(res=>{//6:获取返回结果 提示 重新加载数据[刷新]if(res.data.code==1){this.$toast("删除成功");this.loadMore();//重新加载数据 刷新}})}).catch(err=>{//用户点击取消按钮})},loadMore(){console.log(123);//发送请求获取购物车数据//1:创建变量url保存请求服务器程序地址var url = "findcart";//2:发送ajax请求并且获取服务器返回数据this.axios.get(url).then(res=>{//3:获取服务器返回数据 code==-2// 提示请登录 跳转Login组件if(res.data.code==-2){this.$toast("请登录");this.$router.push("/Login");return;}else{//4:获取服务器返回数据 code==1//5:将服务器返回购物车列表保存listthis.list = res.data.data;//console.log(this.list);//6:在模板中创建循环显示购物车列表数据即可 }})}}}</script><style scoped>/*1:一个商品项目元素*/.cartItem{display:flex;/*弹性布局*/justify-content: space-between;/*子元素两端对齐*/align-items: center;/*子元素垂直居中*/border-bottom:1px solid #ccc;margin-top:25px;/*商品之间间距*/}/*2:左侧【商品名称与价格】*/.leftImgTxt{display: flex;align-items: center;}.title{margin-left:15px;}</style>

vue_app_00_null/src/router/index.js

import Vue from 'vue'//引入Vue对象import Router from 'vue-router'//引入路由//引入自定义组件//1:引入组件Login.vueimport Login from "../components/2.21/xz/Login.vue"import Product from "../components/2.21/xz/Product.vue"import Cart from "../components/2.21/xz/Cart.vue"Vue.use(Router)export default new Router({//配置组件-:访问路径routes: [{path:'/Login',component:Login},{path:'/Product',component:Product},{path:'/Cart',component:Cart}]})//打浏览器地址 http://127.0.0.1:8080/#/Cart// "/"当前项目 "#"分隔符 "/"路径

保存引入组件路径文件,脚手架终端也会更新 终端代码DONE Compiled successfully in 178ms ,打开路径进入浏览器查看引入是否有误

查询购物车组件 Cart.vue

查询当前登录用户购物车列表

服务器: GET /findcart

脚手架组件Cart.vue

当组件创建成功后立即发送ajax请求 GET /findcart

服务器返回值

{code:-2,msg:“请求登录”} this.$router.push("/Login")

{code:1,msg:“查询成功”,data:[…]} res.data.data //第一个data是框架发请求所有用户都保存在data中 , 第二个是服务器保存数组的data,此处接收

常见错误二

登录成功后查询购物车,又跳转登录页面请求登录

问题根源 : session对象失效

解决问题 :

脚手架项目main.js中axios.defaults.withCredentials=true位置出错

服务器端 app.js 配置写错

server.use(session({

secret:“128位安全字符串”,//加密条件

resave:true,//每次请求更新数据

saveUninitialized:true,//保存初始化数据

}));

app.js功能五:删除购物车中一条商品信息

购物车第二个功能 : 删除一个指定商品

注意事项

(1)删除商品为什么id

原因:id INT 主键 #删除速度极快

lname VARCHAR #速度慢

查询某一个商品;更新一个商品;删除一个商品 , id作为首选条件

(2)删除是一种有危险性操作 , 删除数据极难恢复

实现功能 :

数据库表 xz_cart(id;lid;lname;price;count;uid)

中间人

接收脚手架组件传递数据 id

sql DELETE FROM xz_cart WHERE id = ? AND uid = ?

json {code:1,msg:“删除成功”}

脚手架组件

<mt-button @click="del(item.id)"></mt-button>

del(id){

显示确认框:是否删除指定商品 确认 取消

url obj get

重新加载数据

}

全选按钮 Cart.vue

全选<input type="checkbox" />Cart.vue

当选中全选按钮 所有商品前复选框 选中当清空全选按钮 所有商品前复选框 清空如果手工选中所有商品 全选选中如果清除某一个商品选中状态 全选清空

常规解决方案 :

全选按钮绑定v-model="allcb"变量<input type="checkbox" v-model="allcb" />

商品放在list里,加个属性cb显示商品前面选中状态list:[{cb:false,id:1,lname:"aa"},{cb:false,id:2,lname:"bb"}]

商品前面加一个事件@change=“itemChange”<input type="checkbox" v-model="item.cb" @change="itemChange"/>itemChange函数计算商品前面选中(cb:true)数allcb等于商品数

删除选中的商品 Cart.vue

分析组件

[

{cb:false,id:1,lname:“mac”},

{cb:true,id:2,lname:“7888”},

{cb:true,id:3,lname:“7488”}

]

“2,3” 删除编号为2编号为3商品

分析中间人app.js

参数:id=“2,3”

sql:"DELETE FROM xz_cart WHERE id =2 or id =3"

"DELETE FROM xz_cart WHERE id IN(2,3)"

写组件功能

购物车中商品数量 vuex

作用:vuex 脚手架全局变量保存多个组件共享数据

vuex安装配置与使用

vuex特点

集合式存储多个组件共享数据(全局共享)

如果vuex中保存数据发生更新vuex通知所有使用此数据组件修改数据

vuex下载 : 脚手架文件夹下打开cmd 输入指令npm i vuex安装

vue_app_00_null >npm i vuex

vuex 配置 main.js

引入vuex 组件import Vuex from "vuex"

注册Vue.use(Vuex)

创建存储对象(!!)var store = new Vuex.Store({})

将存储对象添加到vue实例中

new Vue({

store

})

语法 :

var store = new Vuex.Store({

store:{ //保存全局数据

fa:12 //亮哥头发根数

},

//如何需要获取全局数据或者修改此数据需要通过函数调用

mutations:{//保存修改全局数据函数

subFa(state){state.fa- -}//state.fa减减

},

getters:{ //获取全局数据函数

getFa(state){return state.fa}

}

}) //subFa getFa 是自定义函数名

vuex 使用 :

在模板中获取数据

<template><div>亮哥有几根头发<span>{{$store.getters.getFa}}</span></div></template>

修改全局数据(js)this.$mit("subFa")

查询全选删除购物车 Cart.vue

vue_app_00_null/src/components/2.21/xz/Cart.vue

<template><div><!--h3>Cart.vue 购物车</h3--><!--(1)顶部全选复选框--><div class="selectall">全选<input type="checkbox" v-model="allcb" @change="selectAll"/></div><!--(2)购物车商品列表 --><div class="cartItem" v-for="(item,i) of list" :key="i"><div class="leftImgTxt"><input type="checkbox" v-model="item.cb" @change="changeItem"/><div class="title">{{item.lname}}</div><div class="title">{{item.price}}</div></div><mt-button @click="del(item.id)">删</mt-button></div><!--(3)一组按钮--><div>购物车中商品数量<span style="color:red">{{$store.getters.getCartCount}} </span><mt-button @click="delm">删除选中商品</mt-button><mt-button>清空购物车</mt-button></div></div></template><script>export default {data(){return {list:[], //购物车购物信息allcb:false, //全选按钮状态}},created(){//组件创建成功后获取购物车列表信息this.loadMore(); },methods:{sub(){//功能:修改全局共享数据fathis.$mit("subFa"); },delm(){//功能:删除选中商品//1:判断商品数量如果数量为0 this.list//2:显示确认框 当前没有可删除商品//3:返回if(this.list.length==0){this.$messagebox("消息","当前没有可删除商品");return;}//4:创建变量str 目的拼接字符串 "2,3,4"var str = "";//5:创建循环遍历数组 this.list//6:判断当前商品是否是选中状态 cb==true// 获取id拼接字符串str+","for(var item of this.list){if(item.cb){str+=item.id+","}}//str = "";//7:判断:如果用户没有选中商品str.length==0//8:显示确认框 请选择要删除的商品if(str.length==0){this.$messagebox("消息","请选择需要删除的商品");return; }//8.1:截取字符串 "2,3,"=>"2,3"str = str.substring(0,str.length-1);//9:显示确认交互框 是否删除指数据//10:创建变量 url obj//11:发送ajax请求删除指定数据this.$messagebox.confirm("是否删除指定商品?").then(res=>{//用户选中 确认按钮var url = "delm";var obj = {id:str};this.axios.get(url,{params:obj}).then(res=>{//重新请求数据刷新页面this.loadMore();this.$toast("删除成功")})}).catch(err=>{})//用户选中 取消按钮 },selectAll(){//功能:全选按钮状态修改操作//1:获取全选按钮状态var cb = this.allcb;//2:创建循环遍历所有商品状态赋值for(var item of this.list){item.cb = cb;}},changeItem(){//功能:商品状态修改操作//功能一:累加商品状态为truevar sum=0;for(var item of this.list){if(item.cb)sum++;}//功能二:判断如果商品总数量与等于true总数量相同if(this.list.length==sum){this.allcb = true;}else{this.allcb = false;}},del(id){//功能:删除购物车中指定商品console.log(id);//1:显示交互对话框this.$messagebox.confirm("是否删除指定商品?").then(res=>{//用户点击确认按钮//2:如果有户选中 确认//3:创建变量url 保存中间人删除程序地直 /delvar url = "del";//4:创建变量obj 保存idvar obj = {id}//5:发送ajax请求this.axios.get(url,{params:obj}).then(res=>{//6:获取返回结果 提示 重新加载数据[刷新]if(res.data.code==1){this.$toast("删除成功");this.loadMore();}})}).catch(err=>{//用户点击取消按钮})},loadMore(){console.log(123);//发送请求获取购物车数据//1:创建变量url保存请求服务器程序地址var url = "findcart";//2:发送ajax请求并且获取服务器返回数据this.axios.get(url).then(res=>{//3:获取服务器返回数据 code==-2// 提示请登录 跳转Login组件if(res.data.code==-2){this.$toast("请登录");this.$router.push("/Login");return;}else{//4:获取服务器返回数据 code==1//5:将服务器返回购物车列表保存list//this.list = res.data.data;//注意:以下程序顺序//5.1:获取服务器中购物车列表,临时保存变量rowsvar rows = res.data.data;//5.2:创建循环遍历数组中每一个商品并且添加cb属性// 表示商品是否选中状态for(var item of rows){item.cb = false;}//5.3:将新数组赋值listthis.list = rows;//console.log(this.list);//6:在模板中创建循环显示购物车列表数据即可//7:修改购物车全局数据var sum = 0;for(var item of this.list){sum+=item.count;}this.$mit("addmCart",sum);}})}}}</script><style scoped>/*1:一个商品项目元素*/.cartItem{display:flex;/*弹性布局*/justify-content: space-between;/*子元素两端对齐*/align-items: center;/*子元素垂直居中*/border-bottom:1px solid #ccc;margin-top:25px;/*商品之间间距*/}/*2:左侧【商品名称与价格】*/.leftImgTxt{display: flex;align-items: center;}.title{margin-left:15px;}</style>

app.js 功能一 – 功能六

服务器vue_server_00/app.js

//功能:服务器程序//1:引入四个模块const express = require("express"); //web服务器模块const mysql = require("mysql");//mysql模块const session = require("express-session");//session模块const cors = require("cors");//跨域//2:创建连接池var pool = mysql.createPool({host:"127.0.0.1",user:"root",password:"",database:"xz",port:3306,connectionLimit:15})//3:创建web服务器var server = express();//4:配置跨域模块//4.1:允许程序列表 脚手架//4.2:每次请求验证server.use(cors({origin:["http://127.0.0.1:8080","http://localhost:8080"],credentials:true }))//5:指定静态资源目录 publicserver.use(express.static("public"));//6:配置session对象server.use(session({secret:"128位安全字符串",//加密条件resave:true,//每次请求更新数据saveUninitialized:true,//保存初始化数据}));//7:为服务器绑定监听端口 4000server.listen(4000);console.log("服务器起动.......");//功能一:用户登录验证server.get("/login",(req,res)=>{//1:获取脚手架传递用户名和密码var u = req.query.uname;var p = req.query.upwd;//2:创建sql语法并且将用户名和密码加入var sql = "SELECT id FROM xz_login WHERE uname=? AND upwd=md5(?)";//3:执行sql语法并且获取返回结果pool.query(sql,[u,p],(err,result)=>{//3.1:如果出现严重错误抛出 if(err)throw err;//3.2:如果result.length长度为0,表示登录失败if(result.length==0){res.send({code:-1,msg:"用户名或密码有误"});}else{//登录成功//如果用户登录成功:创建session对象并且将登录凭证uid//保存对象中 result=[{id:1}]//将当前登录用户id保存session对象中作业:登录凭证req.session.uid = result[0].id;res.send({code:1,msg:"登录成功"})}});})//测试:你 //启动服务器 node app.js//打开浏览器在地址栏输入//http://127.0.0.1:4000/login?uname=tom&upwd=123//http://127.0.0.1:4000/login?uname=tom&upwd=122//功能二:显示商品列表-(分页)//1:GET /product server.get("/product",(req,res)=>{//2:接收参数 页码 一页几行var pno = req.query.pno;var ps = req.query.pageSize;//3:为参数设置默认值 1 20if(!pno){pno=1}if(!ps){ps=20}//4:创建sql语句分页查询商品列表var sql = "SELECT lid,lname,price,pic FROM xz_laptop LIMIT ?,?";var offset = (pno-1)*ps;ps = parseInt(ps);//5:执行sql语句并且将结果发送脚手架pool.query(sql,[offset,ps],(err,result)=>{if(err)throw err;res.send({code:1,msg:"查询成功",data:result})})})//测试// 1:启动node app.js// 2:http://127.0.0.1:4000/product// 3:http://127.0.0.1:4000/product?pno=2// 4:http://127.0.0.1:4000/01.jpg// 5:http://127.0.0.1:4000/02.jpg//功能三:将商品添加至购物车server.get("/addcart",(req,res)=>{//1:获取当前登录用户凭证var uid = req.session.uid;//2:如果当前用户没有登录凭证 输出请登录if(!uid){res.send({code:-2,msg:"请登录"});return;}//3:获取脚手架传递数据 lid,lname,pricevar lid = req.query.lid;var lname = req.query.lname;var price = req.query.price;//4:创建sql语句 查询当前用户是否购买过此商品var sql = "SELECT id FROM xz_cart WHERE uid=? AND lid=?";//5:执行sql语句pool.query(sql,[uid,lid],(err,result)=>{//6:在回调函数(钩子函数)if(err)throw err;//7:获取查询结果[判断是否购买过此商品]if(result.length==0){//8:如果没买过此商品 创建INSERT SQLvar sql = `INSERT INTO xz_cart VALUES(null,${lid},'${lname}',${price},1,${uid})`;}else{//9:如果己购买过此商品 创建UPDATE SQLvar sql = `UPDATE xz_cart SET count=count+1 WHERE uid=${uid} AND lid=${lid}`;}//10:执行sql//11:返回结果脚手架pool.query(sql,(err,result)=>{if(err)throw err;res.send({code:1,msg:"添加成功"})})})//select end//测试// 1:启动 xmapp 启动mysql // USE xz;// SELECT * FROM xz_cart;// 下载昨天db02.sql 执行//2:启动node node app.js//3:浏览器地址// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa// http://127.0.0.1:4000/login?uname=tom&upwd=123// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa// SELECT * FROM xz_cart;})//功能四:查询指定用户购物车列表server.get("/findcart",(req,res)=>{//1:获取用户登录凭证uidvar uid = req.session.uid;//2:没有uid表示此用户未登录 发送请登录信息if(!uid){res.send({code:-2,msg:"请登录",data:[]});return;}//3:创建sql语句var sql = "SELECT id,lid,lname,price,count FROM xz_cart WHERE uid=?";//4:发送sql语句并且将查询结果返回脚手架pool.query(sql,[uid],(err,result)=>{if(err)throw err;res.send({code:1,msg:"查询成功",data:result});})});//测试// 重新启动node node app.js// 打开浏览器在地址栏 // http://127.0.0.1:4000/findcart #请登录// http://127.0.0.1:4000/login?uname=tom&upwd=123 // http://127.0.0.1:4000/findcart #查询结果// http://127.0.0.1:4000/addcart?lid=1&price=9&lname=aa// http://127.0.0.1:4000/addcart?lid=2&price=9&lname=aa// http://127.0.0.1:4000/findcart #查询结果//功能五:删除购物车中一条商品信息server.get("/del",(req,res)=>{//1:获取用户登录凭证var uid = req.session.uid;//2:如果没有登录凭证 请登录if(!uid){res.send({code:-2,msg:"请登录"});return;}//3:获取脚手架传递数据 idvar id = req.query.id;//4:创建sql依据id删除数据var sql = "DELETE FROM xz_cart WHERE id = ? AND uid=?";//5:执行sql语句获取返回结果pool.query(sql,[id,uid],(err,result)=>{if(err)throw err;//判断删除是否成功 affectedRows 影响行数if(result.affectedRows>0){res.send({code:1,msg:"删除成功"});}else{res.send({code:-1,msg:"删除失败"});}});//6:将结果返回脚手架})//测试// 1: 重新启动 node app.js // select * from xz_cart;// 2: 打开浏览器测 http://127.0.0.1:4000/del?id=1// 3: 打开浏览器测 http://127.0.0.1:4000/login?uname=tom&upwd=123// 4: 打开浏览器测 http://127.0.0.1:4000/del?id=1// 5: 打开浏览器测 http://127.0.0.1:4000/del?id=1//功能六:删除用户指定商品//1:接收请求 /delmserver.get("/delm",(req,res)=>{//2:获取用户登录凭证var uid = req.session.uid;//3:请登录if(!uid){res.send({code:-2,msg:"请登录"});return;}//4:接收参数 id = "2,3"var id = req.query.id;//5:创建sql语句执行删除多条记录功能var sql = `DELETE FROM xz_cart WHERE id IN (${id})`;//6:判断是否删除成功 并且返回值pool.query(sql,(err,result)=>{if(err)throw err;if(result.affectedRows>0){res.send({code:1,msg:"删除成功"})}else{res.send({code:-1,msg:"删除失败"})}})})//测试// 1:查询mysql xz_cart 表几个id// 2:重新启动node app.js// 3:打开浏览器// http://127.0.0.1:4000/delm?id=2,3// http://127.0.0.1:4000/login?uname=tom&upwd=123// http://127.0.0.1:4000/delm?id=2,3

脚手架引入需要的组件库vue_app_00_null/src/main.js

import Vue from 'vue' //vue实例对象import App from './App.vue' //根组件import router from './router'//路由模块//选择代码 main.js 5~75 删除 删除!!!//选择一行代码删除 //功能一:引入和配置mint-ui组件库//1:引入mint-ui所有组件import MintUI from "mint-ui"//2:单独引入mint-ui样式文件import "mint-ui/lib/style.css"//3:将mint-ui对象注册Vue实例 34Vue.use(MintUI);//功能二:引入图标字体中样式文件,使所有自定义组件均可使用import "./font/iconfont.css"//功能三:引入axios库//1:引入axios库import axios from "axios"//2:配置访问服务器基础路径axios.defaults.baseURL="http://127.0.0.1:4000/"//3:配置保存session数据axios.defaults.withCredentials=true//4:注册Vue.prototype.axios = axios;//功能四:引入全局对象vuex存储数据//1:引入vueximport Vuex from "vuex";//2:注册vuexVue.use(Vuex);//3:创建存储对象var store = new Vuex.Store({state:{//全局共享数据fa:12,//亮哥头发数量cartCount:0,//购物车中商品数量},mutations:{//所有修改全局共享数据函数subFa(state){state.fa--},subCart(state){state.cartCount--},//减一个addmCart(state,n){state.cartCount=n},//加多个clearCart(state){state.cartCount=0},//清空购物车数量},getters:{//所有获取全局共享数函数getFa(state){return state.fa},getCartCount(state){return state.cartCount}}})//以下代码一定在main.js最后new Vue({router, //路由对象render: h => h(App),store //4:将存储对象添加vue实例中}).$mount('#app')

启动数据库 服务器 脚手架

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。