简单电商项目代码地址:https://github.com/Betty09Zhang/shoppingMall
效果浏览:www.bettyzm.clude:4000/index.html 登录名:zm 密码:123
全局模态框组件实现:
在modal.vue 中添加槽
在父组件中直接添加组件
请先登录!
在子组件中引入isShow 变量 props["isShow"]
通过触发在父组件定义的事件 如close =====> 执行父组件中定义的closeModal 方法。
methods:{
closeModal(){
this.isShow=false;
},
在子组件中,通过this.$emit('close') 触发
emit/on 事件发布 和订阅
模拟mock 数据,json 文件验证,不用后台数据。
头部:mint-ui headbar
底部:m-ui tarbar www.dcloud.io/hellomui (可更换ICON 图标)
input 搜索框 display:inline-block 转换为行内块才能一行显示。
加载商品图片时, 图片需要动态赋值,否则渲染DOM树是,图像来不及加载。动态加载时,一开始无SRC属性,就不会造成图像路径找不到的错误,使用命令后,需要用单引号将其引入,因为使用命令后,就要使用js 语句,不再是字符串,要使用字符串时必须用单引号引入。
客户端发出请求,可用axios插件。
基于promise用于浏览器和node.js的http客户端
axois npm 安装后,导入模块以后,需要将其挂载为vue 的原型对象才能使用
Vue.prototype.$axios=axios
//设置响应头response header
var app=express()
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
next();
});
在 利用axios跨域接收 服务器响应的cookie 时,这是不能设置响应头 res.header("Access-Control-Allow-Origin", "*");必须指定具体前端页面的域名和端口。在响应头里面加上MIME TYPE 的类型。
eg: res.header("Access-Control-Allow-Origin", "http://127.0.0.1:8080");
res.header("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("Content-Type", "application/json;charset=utf-8");
开发时,webpack -dev -server 默认是以本地地址 http://localhost/8080 打开前端页面,要指定具体的域来打开,不要用localhost,否则 服务器响应的cookie 不会由axios跨域访问写到客户端
设置cookie 利用express封装的方法 response.cookie("userId",value); 获取cookie request.headers.cookie。
在使用axio 请求时,在then 的内部不能使用vue 的实例化this ,因为在内部没有被绑定。
解决方案:用es6 箭头函数,箭头函数可以和父方法共享变量。
export default {
data(){
return {
newsList:[]
}
},
created(){
this.$ajax.get('/news/').then(function(response){
this.newsList=response.data.list;=======>// 注意response.data 才可以接收到响应数据。
console.log(this.newsList);
}).catch(function(error){
console.log(error)
})
}
}
axios get传参请求,添加params 字段,传递参数;
var param={pageSize:this.pageSize,pageIndex:this.pageIndex,sort:this.sortFlag?1:-1};
this.$ajax.get('/goods',{'params':param}).then((response)=>{...
Vue实例中有$route 和$router 属性,可通过控制台输出this 查看。
在Vue2.0 this.$route.query ,this.$route.params 接收router-link 传的参数。
$route 为当前router 跳转对象里面可以获取得name,path,query,params 等。
$router 为 VueRouter 实例,想要导航到不同url,可使用$router.push(‘要跳转的路径名’) 的方法。
服务端express 路由get 方法传参,url中 需用占位符
var router=express.Router();
router.get('/newsDetails/:id',function(req,resp,next){
// resp.send('获取服务端信息 goods');
// 接收到请求后,利用模型取数据库里面查找 有findAPI
var id=req.params.id;
console.log("id:"+id);....
}
注意:初始值 应设置busy 为 false。busy=true 表示禁止加载显示。
url 传值 通过request 获取
http://localhost:4000/goods?pageSize=3&pageIndex=2&sort=1 ==》express 框架取参数: request.query("pageSize");
http://localhost:4000/goods/3 ==》express 框架取参数: request.params("pageSize");
原生nodejs 是通过 request.url
router.get('/',function(req,resp,next){
// resp.send('获取服务端信息 goods');
// 接收到请求后,利用模型取数据库里面查找 有findAPI
var pageIndex=req.query('pageIndex');
console.log(pageIndex);
var pageSize=parseInt(req.param('pageSize'));
var param={};
var nums=pageSize*(pageIndex-1);
var sort=req.param('sort');
var goodsModel=Goods.find(param).skip(nums).limit(pageSize);
goodsModel.sort({'salePrice':sort});
goodsModel.exec(function(err,doc){
if(err){
resp.json({
status: '0',
msg: err
})
}
else{
resp.json({
status:'1',
msg: '',
count: doc.length,
list:doc
})
}
})
})
通过request.body.属性 来获取参数。
注意:在浏览器端定义完数据模型model 后记得导出 module.exports=mongoose.model('Users',userSchema);
日期时间转换 : 定义为Date 日期型格式数据从数据库取出数据时格式为 2015-04-23T00:00:00.000Z,可用moment 日期转换时间插件来转化。在main.js 中定义一个过滤器即可。
response.json({}) // 输出json 格式数据
response.end() // 输出字符串格式数据
router.get('/',function(req,res,next){
})
var app=express()
app.use(router) =========> 设置完路由之后 ,记得挂载路由。
跑起来发现图片不显示,错误码为404,
原因:在webpack中会将图片图片来当做模块来用,因为是动态加载的,所以url-loader将无法解析图片地址,然后npm run dev 或者npm run build之后导致路径没有被加工【被webpack解析到的路径都会被解析为/static/img/[filename].png,完整地址为localhost:8080/static/img/[filename].png】
js动态生成的路径无法被url-loader解析到,如果你去build,会发现图片甚至不会打包输出到dist目录(webpack是按需打包的)。
解决办法:①将图片作为模块加载进去,比如images:[{src:require(‘./1.png’)},{src:require(‘./2.png’)}]这样webpack就能将其解析。②将图片放到static目录下,但必须写成绝对路径如images:[{src:”/static/1.png”},{src:”/static/2.png”}]这样图片也会显示出来,任何放在static/中文件需要以绝对路径的形式引用:/static[filename]
设置 链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 linkActiveClass
来全局配置。
./
: 当前目录下; ./component 表示当前目录同级component文件目录
../
: 父级目录;
定义一个css 文件,在main.js 中引入(import 即可)
采用express 中间件
app.use(function(req,resp,next){
console.log("req.originalUrl: "+req.originalUrl);
console.log("req.path: "+req.path);
console.log("cookie:"+req.headers.cookie);
if(req.headers.cookie){
console.log('已登录');
next();
}
else{
//白名单
if(req.originalUrl=='/users/logout' || req.originalUrl=='/users/login' || req.originalUrl=='/news/newsList' || (req.originalUrl.indexOf('/goods/list')>-1)){
console.log('白名单 通过!');
next();
}
else{
console.log('请先登录!');
resp.json({ ====> 传数据到前端===> 前端根据状态码 弹框提示
status:'0',
msg:'请登录',
result:''
});
}
}
})
enter 登录
在密码输入框 中注册 回车键的keyup 时间 @keyup.enter
update 更新mongoose
Users.update({'userId':userId,'cartList.productId':productId},{'cartList.$.productNum':productNum,'cartList.$.checked':checked},function(err,doc){
if(err){
resp.json({
status: '0',
msg: err.message
})
}
else{
resp.json({
status:'1',
msg:'',
result:'success'
});
}
})
1.监控商品选中框状态,是否选中全选按钮。
2. 监控商品数量按钮,实时改变价格。
在computed 属性中定义变量: 例子:
|
computed:{ allSelectedFlag(){ for(var i=0;i countSum(){ |
import 导入
在 export default{} 中 定义过滤器 filters: {
过滤器名称:导入模块名
}
import {currency} from '.././util/currency.js'
export default{
data(){
return{
cartList:[],
isShow:false,
productId:'',
}
},
mounted(){
this.getCart();
},
filters:{
currency: currency
},
import 导入 Vue.filter(过滤器名称,导入模块名);
| 过滤器名称 使用
import './util/currency.js'
//挂载
Vue.prototype.$ajax=Axios;
Axios.defaults.baseURL='http://127.0.0.1:4000';
Axios.defaults.withCredentials=true;
Vue.filter('converDate',function(value) {
return Moment(value).format('YYYY-MM-DD');
});
Vue.filter('currency',currency);
this.$router.push({path: '/user/item?addressId='+ temp})
在项目中如购物车的数量等需要实时的在各个单页面统一更新,若利用父子组件通信传值,则较不方便,若有一个全局的变量来进行更新,则方便许多,在mutations 中通过commit 方法修改变量值,需要用到的数据封装成一个对象payload,一起传过去。
npm install vuex --save
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
在vue 中注册。
var store=new Vuex.Store({
state:{
count:0
},
mutations:{
getCount(state,payload){
if(payload.flag=='add'){
console.log('数量count:'+store.state.count);
console.log('数量传参:'+payload.count);
store.state.count+=payload.count;
console.log('数量结果:'+store.state.count);
}
else if(payload.flag=='minus'){
store.state.count-=payload.count;
}
}
}
})
new Vue({
el:'#myapp',
store,
router: router,
render: function(create){
return create(App);
}
})
在组件footer.vue 中
methods:{
getCart(){
this.$ajax.get('/users/cart').then((response)=>{
if(response){
var re=response.data;
if(re.status=='1'){
this.cartList=re.result.cartList;
console.log('购物车数量:'+re.cartCount);
var payload={
flag:'add',
count: re.cartCount
}
this.$store.commit("getCount",payload);
}
}
else{
console.log('获取购物车失败!');
}
})
}
在 style 中引入css ,scss 文件 @import '../../style/mixin' ; 分号分割;
定义 animation动画 @keyframes tipMove{
0%{ transform: scale(1)}
}