Vue-cms
头部的固定导航栏使用
Mint-UI
的Header
组件;
底部的页签使用 mui
的 tabbar
;
先把 扩展图标的 css 样式和扩展字体库 ttf 文件,拷贝到 项目中
按需导入
// 引入Tabbar模块
import './lib/mui/css/mui.min.css'
import './lib/mui/css/icons-extra.css'
import './lib/mui/fonts/mui-icons-extra.ttf'
引用
router-link
来实现单页面的切换;router-view
来展示路由匹配到的组件设置路由
Tab Bar 路由激活时高亮 linkActiveClass: 'mui-active'
router-view
用transition
包起来.v-leave-to
中设置position: absolute;
translate(-100%);
和translate(100%);
npm install vue-source
import Vueresource from 'vue-resource'
Vue.use(Vueresource)
v-for="item in LunboList" :key="item.id"
:
==> :src
import { Toast } from 'mint-ui'
this.LunboList = result.body.message
a
-> router-link
to /home/newslist
dispaly:flex
justify-content:space-between
设置请求的根目录
Vue.http.options.root = 'http://www.liulongbin.top:3005';
发送请求
注意:Note that for the root option to work, the path of the request must be relative. This will use this the root option:
Vue.http.get('someUrl')
while this will not:Vue.http.get('/someUrl')
this.$http.get('api/getnewslist').then()
将数据存放到数组中
在created中调用
v-for
:key
:src
javaScript日期处理类库:Moment.js
npm i moment
import moment from 'moment'
全局
的过滤器
{{item.add_time | dateFormat }}
{path:'/home/newsinfo/:id'}
id : this.$router.params.id
v-html
scoped
导入
注册components:{}
写入页面
样式
:id=this.id
props:["id"]
pageIndex:1
i+1
楼注册点击事件
pageIndex++
每当获取新评论数据的时候,不要把老数据清空覆盖,而是应该以老数据,拼接上新数据
```js
```
this.comments = this.comments.concat(result.body.message)
```
文本框双向数据绑定
校验评论内容是否为空
发送请求
全局设置post的表单数据格式
this.$http.post(
'api/postcomment/'+this.id,
{content:this.content},
{emulateJSON:true})
.then()
//Vue.http.options.emulateJSON = true; //全局设置MIME类型
this.$http.post(
'api/postcomment/'+this.id,
{content:this.content})
.then()
拼接评论对象,用unshift添加到数组
使用MUI
去掉mui-fullscreen
初始化
import mui from '../../../lib/mui/js/mui.min.js'
Uncaught TypeError: ‘caller’, ‘callee’, and ‘arguments’ properties may not be accessed on strict mode functions or the arguments objects for calls to them
“调用者”、“被调用者”和“参数”属性可能不会在严格模式函数或调用它们的参数对象上被访问
移出严格模式: babel-plugin-transform-remove-strict-mode
- 安装
npm install babel-plugin-transform-remove-strict-mode
- .babelrc文件设置:
"plugins": ["transform-remove-strict-mode"]
tab-top-webview-main
组件第一次显示到页面中的时候,无法被滑动解决: 在 组件的
mounted
事件钩子中,注册 mui 的滚动事件:
mounted() {
// 需要在组件的 mounted 事件钩子中,注册 mui 的 scroll 滚动事件
mui('.mui-scroll-wrapper').scroll({
deceleration: 0.0005 //flick 减速系数,系数越大,滚动速度越慢,滚动距离越小,默认值0.0006
});
}
Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080
http://www.cnblogs.com/pearl07/p/6589114.html
https://developer.mozilla.org/zh-CN/docs/Web/CSS/touch-action
和 App.vue 中的
router-link
身上的类名mui-tab-item
存在兼容性问题,导致tab栏失效,可以把mui-tab-item
改名为mui-tab-item1
,并复制相关的类样式,来解决这个问题;
.mui-bar-tab .mui-tab-item1.mui-active {
color: #007aff;
}
.mui-bar-tab .mui-tab-item1 {
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-item1 .mui-icon {
top: 3px;
width: 24px;
height: 24px;
padding-top: 0;
padding-bottom: 0;
}
.mui-bar-tab .mui-tab-item1 .mui-icon~.mui-tab-label {
font-size: 11px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
this.imgcategory.unshift(category)
:class="['mui-control-item', item.id == 0 ? 'mui-active':'']"
//main.js
import MintUI from 'mint-ui'
Vue.use(MintUI)
// mint-ui样式
import 'mint-ui/lib/style.css'
created(){this.getimagesByCateId(0)}
@tap="getimagesByCateId(item.id)"
vertical-align:"middle"
box-shadow: 0 0 9px #999;
background:rgba(0,0,0,0.4)
max-height:84px;
页面及路由
li->router-link tag="li"
:to="'/home/photolist/photoinfo/'+item.id"
插入评论组件
vue-preview
装包npm i [email protected]
(老版本)
img标签上的class不能去掉
每个图片数据中必须有w和h属性
this.thumimages.forEach(item=>{
item.w = 600,
item.h = 400
}
垂直均匀分布
display: flex;
flex-direction: column;
justify-content: space-between;
####编程式导航
在网页中有两种跳转方式
this.$router.push({ name: '组件名称', params: { userId }})
实现跳转
this.$router.push
方法
godetail(id){
this.$router.push({name:'goodsinfo',params:{goodsid:id}})
}
路由
{path:'/home/goodslist/goodsinfo/:goodsid',component:goodsinfo,name:'goodsinfo'}
$route
与 $router
this.$route是路由参数对象,params,query等都属于它
this.$router是有个路由导航对象,可以使用JS代码实现路由的前进后退跳转
抽离轮播图为组件
父向子传数据
:src问题解决:
result.body.message.forEach(item=>{
item.img = item.src
})
Vue绑定class :class="{'full':isFull}"
购买数量组件
单独封装一个子组件
使用mui–>numbox
初始化数字选择框钻组件
import mui from '../../lib/mui/js/mui.min.js'
export default {
mounted(){
//mounted是实例创建期间的最后一个生命周期函数
//已经渲染到页面上了
mui('.mui-numbox').numbox()
}
}
渲染数据
编程式导航跳转goDesc(id){this.$router.push()}
图片问题
width:100%
组件中引用comment组件
定位
半场动画,需要用钩子函数
enter(el,done){
// 优化:
// 1.计算小球初始位置
const ballPosition = this.$refs.ball.getBoundingClientRect()
// console.log(ballPosition)
//DOMRect {bottom: 279,height: 15,left: 150,right: 165,top: 264,width: 15,x: 150,y: 264}
//2. 获取徽标在页面中的位置
const badgePosition = document.getElementById('badge').getBoundingClientRect()
//3.计算距离
var movex = badgePosition.left - ballPosition.left
var movey = badgePosition.top - ballPosition.top
console.log(movex,movey)
el.offsetWidth
el.style.transition = 'all 1s cubic-bezier(.4,-0.3,1,.68)'
el.style.transform = `translate(${movex}px,${movey}px)`
done()
}
父向子传最大值
通过watch属性监听max
watch:{
max : function (nVal,oVal) {
//动态设置数字框最大值
mui('.mui-numbox').numbox().setOption('max',nVal)
}
}
父
@numberVal="getnumber
getnumber(data){ this.numbox = data }
子
为input框绑定事件@change="changeCount"
向父传值
changeCount(){
var num = parseInt(this.$refs.number.value)
this.$emit('numberVal',num)
}
vuex是为了保存组件之间共享数据而诞生的,是一个全局的共享数据存储区域,就相当于是一个数据的仓库
- props,data和vuex的区别
安装npm i vuex
创建实例
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state:{//存放数据
},
mutations:{
//mutations的函数列表中最多支持两个参数
//- 参数1:state状态
//- 参数2:通过commit提交过来的参数(可传一个对象)
},
getters:{
//getters只负责对外提供数据,不负责修改数据
}
})
将vuex实例挂载到vue实例上
this.$store.state.***
this.$store.commit('方法的名称',唯一的一个参数)
this.$store.getters.***
点击事件
addToShopCar (){
var goodsinfo={id,count, price,selected}
// 调用store-->mutations-->addInfoToCar
this.$store.commit('addInfoToCar',goodsinfo)
}
调用mutations里的addInfoToCar方法
addInfoToCar(state,goodsinfo){
// 将商品信息添加到car中
// 如果购物车中已有该商品则只需增加数量,否则添加整个信息
var flag = false //假设购物车中没有该商品
state.car.some(item => {
if (item.id == goodsinfo.id) {
item.count += parseInt(goodsinfo.count)
flag = true
return true
}
})
if(!flag) {
state.car.push(goodsinfo)
}
}
getters
getCount(state){
var c = 0
state.car.forEach(item=>{
c += item.count
})
return c
}
调用{{this.$store.getters.getCount}}
addInfoToCar()
// 当更新car后,将car数组存储在localStorage中
localStorage.setItem('car',JSON.stringify(state.car))
获取car
// 获取localStorage中的car数组
var car = JSON.parse(localStorage.getItem('car') || '[]')
const store = new Vuex.Store({
state:{
car:car
},
})
getGoodsCount(state) {
var o ={}
state.car.forEach(item=>{
o[item.id] = item.count
})
return o;
}
changeCt(){
// 将num同步到store中
this.$store.commit('updateCar',{
count : this.$refs.numbers.value,
id : this.goodsid
})
}
updateCar(state,info){
state.car.some(item=>{
if(item.id == info.id){
item.count = parseInt(info.count)
return true;
}
// return true; //记住啊,这个bug让你废了一天!
})
localStorage.setItem('car',JSON.stringify(state.car))
}
delgoods(id,i){
// 列表删除
this.infolist.splice(i,1)
// store删除
this.$store.commit('delgoods',id)
}
//mutations
delgoods(state,id){
state.car.some((item,i)=>{
if(item.id == id){
state.car.splice(i,1)
return true
}
})
localStorage.setItem('car',JSON.stringify(state.car))
}
<mt-switch v-model="$store.getters.getSelected[item.id]" @change="switchChange">mt-switch>
//getters
getSelected(state){
var s = {}
state.car.forEach(item=>{
s[item.id] = item.selected
})
return s //返回的是一个对象
}
<mt-switch
v-model="$store.getters.getSelected[item.id]"
@change="switchChange(item.id,$store.getters.getSelected[item.id])">mt-switch>
switchChange(id,selected){
this.$store.commit('switchChange',{
id:id,
selected:selected
})
}
//mutations
switchChange(state,info){
state.car.forEach(item=>{
if(item.id == info.id) {
item.selected = info.selected
}
})
localStorage.setItem('car',JSON.stringify(state.car))
}
数量
//getters
getSelectedCount(state){
var selectedCount = 0
state.car.forEach(item=>{
if(item.selected == true){
selectedCount += item.count
}
})
return selectedCount;
}
总价
//getters
getSumPrice(state){
var sum = 0
state.car.forEach(item=>{
if(item.selected == true){
sum += item.count * item.price
}
})
return sum;
}
点击按钮–>编程式导航this.$router.go(-1)
首页不显示返回
v-show="flag"
监听地址 $route.path
watch:{
"$route.path":function(nVal,oVal){
if(nVal == '/home') {
this.flag = false
} else {
this.flag = true
}
}
}
刷新判断是否是首页
created(){
this.flag = this.$route.path == '/home'? false : true
}
–host 192.168.43.202
将项目托管到Apache并启用Gzip压缩
webpack
127.0.0.1:80
中打开要让apache支持gzip功能,要用到deflate_Module和headers_Module。打开apache的配置文件httpd.conf,大约在105行左右,找到以下两行内容:(这两行不是连续在一起的)
#LoadModule deflate_module modules/mod_deflate.so
#LoadModule headers_module modules/mod_headers.so
然后将其前面的“#”注释删掉,表示开启gzip压缩功能。开启以后还需要进行相关配置。在httpd.conf文件的最后添加以下内容即可:
#必须的,就像一个开关一样,告诉apache对传输到浏览器的内容进行压缩
SetOutputFilter DEFLATE
DeflateCompressionLevel 9
最少需要加上以上内容,才可以生gzip功能生效。由于没有做其它的额外配置,所以其它相关的配置均使用Apache的默认设置。这里说一下参数“DeflateCompressionLevel”,它表示压缩级别,值从1到9,值越大表示压缩的越厉害。