vue个人开发项目搭建心得

vue-cli搭建项目

1.确保安装了node与npm

2.再目标文件夹下打开终端

3.执行cnpm i vue-cli -g全局安装


以上安装完成后下次搭建不需再写

1.运行vue init webpack vue_mall(项目名称)

2.进入项目文件夹下执行cnpm install安装package.json的依赖文件

3.运行项目执行npm run dev

关于每个组件内属性的顺序

多人开发时尽量保持每个组件 export default {} 内的方法顺序一致,方便查找对应的方法。

推荐: data(方法)、props(数组)、钩子(方法)、watch(对象)、computed(对象)、components(对象)

组件

· 在组件里的template里写上html(注意要有个根元素,一般为div)

· 在组件里的style里写上css样式(如果不是作用于全局的样式,一般在style后面跟上scoped,但是要是加了反而改变了原有的样式,就不要加)

注册

1.全局注册

Vue.component('my-component', {  //在main.js中

// 选项

})

2.局部注册

components: {

// 将只在父组件模板中可用

'my-component': Child    //es6语法:相同时可只写一个

}

vue-router

1.导入vue-router(main.js)

import vueRouter from 'vue-router'

2.html写代码

写触发链接的标签(按需,没有可不写)

新闻列表

3.路由的占位符

4.javascript中写代码

1.定义组件【不要注册,下面设置路由规则的时候,会自动把我们的组件注册】

在component里新建一个组件xxx.vue

2.创建路由对象,设置路由规则(自动帮我们把组件注册)(router/index.js)

在router/index.js中创建router,并设置routes

const router = new vueRouter({

routes: [{

path: '/site',

component: Layout

}]

}

3.把我们上一步创建的路由对象,注入到根实例,这样我们整个应用就拥有了路由的功能(main.js)

new Vue({

el: '#app',

router,

render: h => h(App)

})

$router&$route

· 相同点:

1.都是属于vue-router里面的

2.必须要在集成vue-router的时候,使用Vue.use(VueRouter),才会在vue原型上面绑定$route、$router这两个属性

· 不同点:

1.$router是在编程式导航的时候,使用到它,它里面有两个方法 $router.push、$router.go

2.$route 用来获取路径中的参数,$route.params.xxx,还可以通过 $route.query.xxx来获取路径中的参数 ,在监控路径变化的时候,使用到它

axios(获取网络请求)

1.导入axios(main.js)

import axios from 'axios'

使用axios(main.js)

Vue.prototype.$axios = axios

axios.defaults.baseURL = 'http://39.108.135.214:8899/'(方便起见可以设置根路由)

axios.defaults.withCredentials = true  (在跨域的时候,允许访问服务器时带上cookies)

2.1发送get请求

    3.1.1 在发起请求组件的methods里添加函数

getGoodsGroup(){

const url = 'site/goods/getgoodsgroup/123'

this.$axios.get(url).then((response)=>{

this.goodsGroup = response.data.message

})

}

  3.1.2 在组件加载前运行该请求函数

created(){this.getGoodsGroup()}

1.2发送post请求

· 与get类似,不过请求参数的设置有所区别

· 有两个格式可选,具体选哪种看后台设置的contentType而定,一般后台两个格式都可以接收

    · this.$axios.post(url,{username:'zhangsan',password:123}).then(response=>{})

    · this.$axios.post(url,"username=zhangsan&password=123").then(response=>{})

导入文件

 · 导入样式

     · 全局导入(main.js)

       import './statics/site/css/style.css'

     · 局部导入

      @import './statics/site/css/style.css'

导入插件

安装

cnpm i xxx -S

导入

import vueRouter from 'vue-router'

全局使用(如果不需要全局使用,则这步可以省略)

2.1 基于vue

Vue.use(vueRouter)

2.2 不基于vue

Vue.prototype.$axios = axios

导入jQuery

1.导入jQuery

安装

cnpm i jquery -S

在build/webpack.base.conf.js里加入

var webpack = require("webpack")

在module.exports的最后加入:

new webpack.optimize.CommonsChunkPlugin('common.js'),

new webpack.ProvidePlugin({

jQuery: "jquery",

$: "jquery"

})

在main.js中引入

import $ from 'jquery'

最后一定要重新npm run dev

2.导入jQuery插件

确保安装了jquery

在script中引入插件js

import '~/site/js/jqueryplugins/jqimgzoom/js/magnifier.js'

在style中引入插件css

@import '../../../static/site/js/jqueryplugins/jqimgzoom/css/magnifier.css';

在script的mounted生命周期钩子中初始化,一般要给其增加延时,以防数据没有请求回来

setTimeout(() => {

$(function () {

$('#magnifier1').imgzoon({

magnifier: '#magnifier1'

});

});

}, 200)

关于router-link

router-link会自动的把该元素变成a标签

添加了to属性后,不需要原来的href属性

to属性动态获取其他值时前面要加冒号(:)

to属性动态拼接时外面的双引号要写在里面所有字符串的外面,固定不变的值外面加上单引号以加号连接外部变量

过滤器

使用:加在双花括号插值表达式中,以管道符号'|'指示:

{{message | dateFmt}}

定义:在局部组件的选项中定义局部过滤器,或者在创建 Vue 实例之前全局定义过滤器

内部的函数可接受多个参数,第一个参数为上面message的值

filters: {  //局部过滤器(xxx.vue)

dateFmt: function (value) {

if (!value) return ''

value = value.toString()

return value.charAt(0).toUpperCase() + value.slice(1)

}

}

Vue.filter('dateFmt',(value,fmt='YYYY-MM-DD')=>{    //全局过滤器(main.js)

return moment(value).format(fmt)

})

new Vue({

// ...

})

关于已定义的数据在模板与vue实例中调用形式

数据在模板中调用直接写属性名

数据在vue实例中调用要在前面写上this,由vue实例调用

关于动画

在最外面的div内定义transition组件,里面放要动画的元素

给要动画的元素设置css过渡样式:

transition: all .5s

给要动画的元素设置显示隐藏:

v-show="isShowPic"

由另一个button设置触发事件,改变isShowPic

给transition组件添加动画钩子:

进入:@before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"

移出:@before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave"

在methods中定义各个动画钩子

beforeEnter: function (el) {

el.style = 'transform:translateX(200px)'

},

enter: function (el, done) {

el.offsetWidth

el.style.transform = 'translateX(0px)'

done()

},

afterEnter: function (el) {

this.isShow = false

},

beforeLeave: function (el) {

el.style = 'transform:translateX(0px)'

},

leave: function (el, done) {

el.offsetWidth

el.style = 'transform:translateX(200px)'

el.addEventListener('transitionend', done)

},

afterLeave: function (el) {

this.isShow = false

}

注意:

el指的是该动画元素

在before里写动画的起始状态或位置、enter或leave里写动画的结束状态或位置

after里写动画的回调函数(如消失隐藏),在enter或leave里调用

关于done在进入时可直接调用,不过在离开时需要在过渡完成事件里调用

在enter或着leave中要添加el.offsetWidth刷新动画帧

关于ref

在dom元素中定义ref属性,则可在vue示例中通过this.refs获取所有有ref属性的dom元素

ref获取不到其父组件所定义ref的dom元素,可用id获取

关于监听路由跳转

在watch属性里添加监听对象$route:对应一个函数,当路由的值发生变化时,重新渲染页面

watch:{// 监控路由变化$route:function(val){// 刷新商品详情和评论数据this.getGoodsinfoData()this.getCommentData()}},

关于vuex

导入vuex,并声明全局使用(main.js)

import Vuex from 'vuex'

Vue.use(Vuex)

创建store对象(main.js)

const store = new Vuex.Store({

state: {

count:1

},

getters:{

//获取state数据

getCount(state){

return state.count

}

},  //对仓库的增删改

mutations: {

addGoods(state,goodsObj){

state.count = addLocal(goodsObj)

}

}

})

注入根实例(main.js)

new Vue({

el: '#app',

router,

store,  //<--见此处

components: { App },

template: ''

})

一般vuex会结合localStorage使用

4.1 新建一个common文件夹,一般与main.js同级,在里面创建一个localTool.js,专门用来写对本地存储的增删改查操作,并暴露出去

4.2 查找

const getLocal = () => {

return JSON.parse(localStorage.getItem('goods') || '{}')

}

3 增加

export const addLocal = (goodsObj) => {

const localGoods = getLocal()

if (localGoods[goodsObj.id]) {

localGoods[goodsObj.id] += goodsObj.count

} else {

localGoods[goodsObj.id] = goodsObj.count

}

localStorage.setItem('goods', JSON.stringify(localGoods))

return getTotal()  //调用其他函数返回一个值

}

在创建store对象前引入localTool.js

import {addLocal} from './common/localTool'

在store对象中添加mutations对象的方法,

示例方法是把值存入本地,调用localTool.js的addLocal方法,并同步state的count

mutations: {

addGoods(state,goodsObj){

state.count = addLocal(goodsObj)

}}

使用

使用mutations对象里的方法

在调用mutation其中方法的组件中,使用:

this.$store.commit('addGoods',goodsObj)

【第一个参数是mutations的方法名,其他可选,是调用过程中会使用的参数】

使用getters获取state(数据)

在使用vuex状态(即数据)的组件中,直接使用:

this.$store.getters.getCount

父子组件传值

一般情况

在父组件中集成子组件

1.1 创建子组件

新建一个vue组件,如:inputnumber.vue

1.2 在父组件中导入子组件

import inputnumber from '../subcomponents/inputnumber'

1.3 在父组件的components中注册子组件

components: { inputnumber }

1.4 直接在父组件的template(模板)中,像自定义标签的形式使用

父组件传值给子组件【通过props】

2.1 接收方 (inputnumber.vue) :子组件

子组件要显式地用 props 选项声明它预期的数据:

props: ['initCount']

2 发送方 (shopcart.vue) :父组件

在使用子组件的地方,即在子组件的标签中,通过 属性名称=值 的方式传值,可动态传值

子组件 把更改之后的值 传回给父组件 【通过自定义事件】

3.1 接收方 (shopcart.vue) :父组件

3.1.1 父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件

@countChange="getChangedCount"

3.1.2 父组件在methods中定义触发自定义事件后的方法

getChangedCount(changedGoods){}    //changedGoods为传回的值

3.2 发送方 (inputnumber.vue):子组件

通过触发事件传值

this.$emit('countChange',{count:this.count})  //值可以是任何类型

element-ui计数器的父子传值

集成组件,设置他的最大和最小值

export default {

data() {

return {

num7: 1

}}};

把要传给计数器的值放在v-model中,即修改v-model的值

把计数器增减后的值传回来

设置change事件(标签),其中第一个参数是另外传给计数器的值,最后一个参数是计数器完成操作后返回的结果

@change="changeCount(item.id, $event)"

设置change事件(methods)

changeCount(value, event){

const goodsObj = {

goodsid:value,

count:event

};

console.log(goodsObj);

}

非父子组件传值

只有在父组件中通过components: { inputnumber }注册的才能称为父子组件,在template通过router-view占位的不算父子组件

新建一个common.js文件,定义一个组件bus作为非父子组件的中转站

import Vue from 'vue'

export const bus = new Vue()

两个组件分别引入bus

import {bus} from '@/common/common'

在发送组件的methods中触发事件

bus.$emit(ISLOGIN,true)

在接收组件的created中监听事件

created(){

bus.$on(ISLOGIN,(logined)=>{

this.isLogin = logined

})

},

点击删除,删除某项数据

数据在后台

发起删除数据请求,获得数据后,重新渲染页面

数据在本地(利用vue的数据驱动,修改data中的值,页面也会相应的变化)

2.1 利用vuex删除本地数据

2.2 在之前获得的渲染页面的数组中,直接删除对应索引的数据

登陆验证

需要登陆验证的组件,在设置该路由规则时,添加元数据(router)

meta:{needLogin:true}

利用导航守卫,给需要登陆验证的组件(即meta有needLogin),发送请求给后台,判断是否登陆(router)

注意:router.beforeEach里一定要有next(),否则路由根本不会跳转

router.beforeEach((to,from,next)=>{

if(to.meta.needLogin){

const url = 'site/account/islogin'

axios.get(url).then(res=>{

if(res.data.code === 'nologin'){

router.push({ name:'login'})    // 去登陆页

}else{

next()  // 正常路由跳转

}

})

}else{

next()

}})

在router.beforeEach中将要跳转的路径保存到本地(router)

if(to.path!='/site/login'){

localStorage.setItem('lastVisited',to.path)

}

在登陆页中登陆成功后,跳转到本地保存的路径(login.vue)

this.$router.push({path:localStorage.getItem('lastVisited')})

发送请求时默认带上cookie(main.js)

axios.defaults.withCredentials = true

返回上一页

直接返回上一页

this.$router.go(-1)

经过登陆验证后,返回他本该去的页面

2.1 在路由守卫中本地保存要去的页面的路径,注意要排除掉/login

if (to.path != '/site/login') {

localStorage.setItem('lastVisited', to.path);

}

2.2 登陆成功时,设置跳到本地保存的路径中

this.$router.push({path:localStorage.getItem('lastVisited')})

Vue组件的生命周期

基本概念

Vue:beforeCreate(组件创建之前)--->created(组件已经创建出来了)--->beforeMount(组件的dom元素被渲染出来之前)--->mounted(dom元素已经渲染出来了)--->【模型数据发生了更改】beforeUpdate(视图重新渲染之前)--->updated(视图已经重新渲染完毕)--->beforeDestory(组件销毁之前)--->destoryed(组件销毁了)

注意点:

1、Vue的一系列生命周期钩子,都是Vue框架提供者,我们开发者,只需要实现,那么我们Vue框架底层就会在恰当的时机,自动调用他们2、每个组件中都有这些生命周期钩子

应用场景:

1、created

发送网络请求,获取数据

2、mounted

等视图渲染完成,然后拿着dom进行操作,有时候可能拿不到dom元素,或者有些效果出不来,可以尝试加200ms的延时如:使用jQuery插件

3、beforeUpdate & update

数据模型发生了更改,会调用,它会重新渲染组件

4、beforeDestory & destory

beforeDestory 记录未提交的数据created 将本地的数据,自动填充上beforeDestory:记录上次滚动到那个地方了created:自动滚动到你上次看得那个位置

使用vue-cli打包

使用npm run build

修改config/index.js里module.exports的assetsPublicPath改为:

assetsPublicPath: './'

修改build/utils.js里generateLoaders的publicPath改为:

publicPath: '../../'

如果引入了jQuery,则在webpack.prod.conf.js里也要声明全局使用,在module.exports的最后加入:

new webpack.optimize.CommonsChunkPlugin('common.js'),

new webpack.ProvidePlugin({

jQuery: "jquery",

$: "jquery"

})

若想删掉自动生成的map文件:

修改config/index.js里module.exports的productionSourceMap改为productionSourceMap: false,

vue-cli优化

删掉.map

.map文件只是帮助我们调试用的,正式上线时可以去掉这个文件

修改config/index.js里module.exports的productionSourceMap改为productionSourceMap: false

element-ui和iview按需导入

element-ui

安装 babel-plugin-component:

cnpm install babel-plugin-component -D

将 .babelrc 修改为:

{

"presets": [

["env", { "modules": false }]

],

"plugins": [["component", {

"libraryName": "element-ui",

"styleLibraryName": "theme-chalk"

}

]]

}

在 main.js 中引入部分组件

如只引入 Button , Select 和 Message

import { Button, Select, Message} from 'element-ui'

Vue.use(Button) //顺便会导入Button的css,不需另外导入

Vue.use(Select)

Vue.prototype.$message = Message //有部分组件不能直接通过use声明全局使用

iview

安装 babel-plugin-import:

cnpm install babel-plugin-import -D

在 .babelrc 中配置:

{

"plugins": [["import", {

"libraryName": "iview",

"libraryDirectory": "src/components"

}]]

}

按需引入组件

import { Button, Table } from 'iview';

Vue.component('Button', Button);

Vue.component('Table', Table);

导入样式

import 'iview/dist/styles/iview.css';

路由懒加载

建议:在刚开始时直接用这种方式引入路由文件

安装babel-plugin-syntax-dynamic-import

cnpm i babel-plugin-syntax-dynamic-import -D

在 .babelrc 中配置:

{

"plugins": ["syntax-dynamic-import"]

}

修改路由中引入文件的方式,把

//(原来)import Layout from '@/components/Layout'

const Layout = () => import('@/components/Layout')

CDN引入

将jquery、moment等大资源的文件通过cdn的方式引入

常见cdn:bootcdn

实现:

引入资源

公开供全局使用,修改bulid文件夹下的webpack.base.conf.js文件

这里小写的vue和vue-router是我们引入资源时对应的名字,冒号后面大写的名字是库的主人所暴露出来的全局方法名,当然这两个名字可以一样

module.exports = {

entry: {

app: './src/main.js'

},

externals:{

'BMap': 'BMap',

'vue': 'Vue',

'vue-router': 'VueRouter'

}

将项目中引用对应资源的地方将原先的引入方式去掉

// import Vue from 'vue'

// import VueRouter from 'vue-router'

BUG

关于渲染值undefined

请求是异步费时操作,在渲染时数据还没有返回回 来,此时就会报undefined错误

虽然之后数据返回后会再次渲染,但刚开始报的错不会消失

v-for不需担心undefined的问题

直接拿数据渲染时可以在其父盒子添加v-if=“渲染数组/对象”,则在没有返回数据时不会渲染页面

关于vue设置属性时,number类型的值设置无效

vue中属性的值为number类型不能直接写label:1,要写:label:“1”

关于css样式与原来不一致

设置css样式的style加了scoped导致,删掉就可还原

在路由中设置了site/login,但是当a标签的href设置为‘/site/login’时不会跳转到对应页面

vue中的无刷新跳转是通过设置url的哈希值(即#)实现的,默认的会在url的末尾添加#,即若href设置为‘#/site/login’,则可以正常跳转

不过vue还是建议我们用router-link来实现跳转,使用时不用担心#的问题

网站本来能正常显示,设置了路由守卫后连首页都打不开了

在设置路由守卫时没有调用next()

由当前页面通过路由跳转显示不同数据时,jquery插件在mounted钩子中初始化后只能显示第一次时的数据

jQuery是事件驱动,vue是数据驱动

同页面的路由跳转并没有销毁并重新打开新的组件,在mounted中初始化的插件,在路由跳转后并不执行初始化函数,所以不能显示

可以把初始化函数放到加载页面数据的请求回来后,这样每次重新渲染页面时就会重新加载初始化函数

一般把jQuery放入axios中

其他

关于foreach和for in

foreach一般用来遍历数组:

myArry.forEach((value,index,arr)=>{

console.log(value);

});

for in一般用来遍历对象:

for(var value in myArry){

console.log(value)

}

关于localStorage

localStorage存的起始都是字符串,所以不能对其中的某个键值对进行增删改查操作

数组化某个localStorage

var contrastdata = JSON.parse(localStorage.getItem('contrastdata'))

对数组进行增删改操作

contrastdata[a] = b

delete contrastdata[a]

contrastdata[a] = c

将操作后的数组存入该localStorage

localStorage.setItem(JSON.stringify(contrastdata))

把数组中对象的某个键对应的值取出来

如:[{id:1,age:2},{id:2,age:4},{id:3,age:5}]

创建一个新数组

const tempArr = []

遍历这个数组,把对象中某个键对应的值放入该数组中

this.shopcartgoods.forEach(item=>{

tempArr.push(item.id)

})

转成字符串

tempArr.join(',')

数组与字符串互转

数组转字符串

var a, b,c;

a = new Array(a,b,c,d,e);

b = a.join('-'); //a-b-c-d-e  使用-拼接数组元素

c = a.join(''); //abcde

字符串转数组

var str = 'ab+c+de';

var a = str.split('+'); // [ab, c, de]

var b = str.split(''); //[a, b, +, c, +, d, e]

作者:Akiko_秋子

链接:https://www.jianshu.com/p/ce1f2db44a79

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(vue个人开发项目搭建心得)