MVC :
后端开发模式
当用户操作了视图层,如果需要进行业务处理,通过ajax发送到服务器,被入口js文件监听到,经过控制器 (路由模块,业务模块)的处理,最终对数据层(数据库的操作)
MVVM
前端的开发模式
MVVM是前端的视图层的分层开发思想, M是数据层,V是视图层,VM用于控制数据的双向绑定,分割了V和M,当V中绑定的数据被修改时,VM会自动将数据层对应的数据进行修改
请求地址 : http://wthrcdn.etouch.cn/weather_mini
请求地址 : http://www.tuling123.com/openapi/api
// YYYY就是年:4个Y代表是要占4位
// MM就是月:2个M就代表2位
// DD就是日:2个DD就代表2位
// HH就是时
// mm就是分
// 除了以上特殊字符,其他你写什么都原样显示
// 如果moment里面不传就代表获取当前时间
var now = moment().format('YYYY年MM月DD日HH:mm');
console.log(now);
// 如果你传入了时间,那么就获得是你传入的时间
var now = moment('1999-01-01 19:35').format('YYYY年MM月DD日HH:mm');
console.log(now);
<script src="./vue.js"></script>
<div id="app"> // Vue控制的元素区域就是视图层View
{{age + 5}} <br>
{{makeCount()}}
</div>
<script>
let vm = new Vue({ // 创建的VM实例对象就是控制器VM
el : '#app',
data : { // data就是Model
name : '龚利明',
age : 18
},
methods : {
makeCount(){
return 1+1;
}
}
})
</script>
class和style例外 : 通过数组来控制data变量的获取
<html lang="en">
<head>
<style>
.type1{
color: red;
}
.type2{
font-size: 40px;
}
</style>
<script src="./../vue.js"></script>
</head>
<body>
// 默认就有的class类的话,加上引号,样式的值也是,加上引号
<div id="app" :class="[aini,{type2 : true}]" :style="[{marginLeft : '100px'},{marginTop : h}]">
你好,我爱你{{name}},我是{{xixi()}}
</div>
<script>
let vm = new Vue({
el : '#app',
data() {
return {
name : '龚利明',
aini : 'type1',
h : '100px'
}
},
methods: {
xixi(){
return '刘诗诗'
}
},
})
</script>
</body>
</html>
<div v-text="msg"></div>
/*********类似于下边代码**************/
<div>{{msg}}</div>
<div v-on:click="makeSomething"></div>
/*********或者下边代码**************/
<div @click="makeSomething"></div>
v-model的修饰符
双向数据绑定的成品
// 1. 控制select
<select v-model="select">
<option value="你好">你好</option>
<option value="北京">你好</option>
<option value="天津">你好</option>
<option value="华山">你好</option>
</select>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
// 1. 一个checkbox的时候处理情况
<input type="checkbox" id="box1" v-model="change" value="aaa"><label for="box1">同意该协议
<p>{{ change }}</p>
<br>
// 2. 多个checkbox的时候处理情况
<input type="checkbox" id="juzi" value="橘子" v-model="choose"><label for="juzi">橘子</label>
<input type="checkbox" id="apple" value="苹果" v-model="choose"><label for="apple">苹果</label>
<input type="checkbox" id="banana" value="香蕉" v-model="choose"><label for="banana">香蕉
<input type="checkbox" id="boluo" value="菠萝" v-model="choose"><label for="boluo">菠萝</label>
<p>{{ choose }}</p>
</div>
<script>
let vm = new Vue({
el:"#app",
data:{
change:true,
choose:[], // 2. 定义个空数组来存储value的值
}
})
</script>
</body>
</html>
<div id="example-4">
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
</div>
new Vue({
el: '#example-4',
data: {
picked: ''
}
})
结果 : Picked: One
<div v-if="age < 18">小于18</div>
<div v-elseif="18>小于18</div>
<div v-else>小于18</div>
指令不被解析
就是说只要标签添加这个属性之后,里边的所有内容就不会执行vue的操作
当页面加载过程中数据还未加载,为了防止页面上很多的vue标签,需要对数据未加载好的进行隐藏, 这里的v-clock需要配合CSS来配合使用
<style>
[v-clock]{display : none}
</style>
<div v-clock>{{name}}</div>
全局自定义指令
Vue.directive('color',{
bind : function(el, color){ // 第一个数字必须为元素的元素DOM对象,第二个参数开始为形参
el.style.color = color.value // 形参.value才能够获取到传递进来的值
},
inserted : function(el){}
update : function(el){}`
})
局部自定义指令
<body>
<div id="app">
<p v-demo> {{msg}} </p>
<p v-aaa="'blue'"> {{msg}} </p>
</div>
<script>
// 定义全局的自定义指令
Vue.directive('demo', function (el) {
el.style.color = 'red';
})
let vm = new Vue({
el: '#app',
data: {
msg: 'nihao'
},
// 定义局部的自定义指令
directives: {
aaa: {
bind : function (el, color) {
el.style.color = color.value;
},
inserted : function(el){},
update : function(el){}
}
}
})
</script>
</body>
自定义属性的简单版本
// 此时的function表示作用域bind和inserted两个函数
directives : {
changeColor: function(el){
el.style.color = 'red'; }
}
Vue.config.kerCodes.名称 = 按键值
Vue.config.keyCodes.f2 = 113
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="box">
<input type="text" v-model="name" id="input">
我叫{{name}},今年{{age}}岁了!
</div>
<script>
// 1. 获取元素
let box = document.getElementById('box');
let input = document.getElementsByTagName('input')
// 2.记录模板的的值
let template = box.innerHTML;
// 3.渲染的原始data值
let _data = {
name : '龚利明',
age : 18
}
// 4.调用perxy监听数据变化
let data = new Proxy(_data,{
set(obj,key,value){
// 让原始的数据变化
_data[key] = value
// 重新渲染这个box的html
render()
}
})
// 5.一加载就渲染
render()
// 渲染的函数
function render(){
box.innerHTML = template.replace(/\{\{\w+\}\}/g,str=>{
str = str.substring(2,str.length-2)
return _data[str]
})
// 渲染input
Array.from(input).filter(ele=>{ // Array.from --> 伪数组转真数组
return ele.getAttribute('v-model')
}).forEach(ele=>{
let nowdata = ele.getAttribute('v-model')
ele.value = _data[nowdata];
// 监听input,从而触发双向绑定
ele.oninput = function(){
data[nowdata] = this.value
}
})
}
</script>
</body>
</html>
使用地点 : 购物车使用, 包括统计当前购物车有多少件商品,统计你选中的商品有多少个. 都有个结果输出,此时从computed作为动态属性加载到页面,随时因为数据变化而变化. 通过set方法,当你主动发生数据改变,可以触发事件,比如全选,全不选都由一个按键来控制
优点 :
例子 :
<body>
<div id="app">
姓 : <input type="text" v-model="xing"><br>
名 : <input type="text" v-model="ming"><br>
<p>{{name}}</p>
<input type="text" v-model="name">
</div>
<script src="../js/vue.js"></script>
<script>
let vm = new Vue({
el : '#app',
data: {
xing : '龚',
ming : '利明'
},
computed: {
// 此处name为对象
name : {
get(){
return this.xing + this.ming;
},
set(value){
if(value == ''){
return
}
this.xing = value[0];
this.ming = value.substring(1)
}
}
},
})
</script>
</body>
<body>
<div id="app">
<input type="text" v-model="xing"><br>
<input type="text" v-model="ming"><br>
<input type="text" v-model="hobby.chi"><br>
<p>{{name}}</p>
<input type="text" v-model="name">
</div>
<script src="../js/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
xing: '龚',
ming: '利明',
hobby: {
chi: '零食',
wan: '天津'
},
},
computed: {
name(){
return this.xing + this.ming;
}
},
watch: {
name(){
console.log(this.name);
},
'hobby.chi' : function(){
console.log('chi变化了!');
}
},
})
</script>
</body>
应用场景 :
作用 : 过滤功能
应用场景 :
原理 : 其实和method没啥区别, 单纯的就是为了语义化. 不然都写在methods不太合适
注意事项 : 一个 |, 并不是 ||, 这个不是或
,仅仅是vue提供的一种格式
{{data | myFormat}}
// 1. 全局过滤
Vue.filter('myFormat',function(data){
return data + '返回的内容';
})
// 2. 局部过滤
let vm = new Vue({
el :'#app',
data : {
data : 'fuck',
},
filters : {
myFormat(data){
return data + '返回的内容'
}
}
})
// 登录验证
http.post(url,sendLogin)
.then(backdata=>{
// 具体传输位置,看接口怎么写
window.sessionStorage.setItem("glmtoken",backdata.data.toklen)
})
登录成功后get方式的请求数据 :
axios.get(url,{
params:{userName : '龚利明', password :'123456'}, // 发送传递数据
headers: { Authorization: window.sessionStorage.getItem("glmtoken") }, // 发送请求头
})
// 引入axios
import axios from 'axios'
//引入vue
import Vue from 'vue'
// 引入路由
import Router from '../router/index'
// !!! 设置这个axios的请求跟路径,以后用相对路径就好了,并且暴露出去
export const http = axios.create({
baseURL: 'http://localhost:8888/api/private/v1/',
})
// 添加请求拦截器
http.interceptors.request.use(function (config) {
// 在发送请求之前做些什么?
// 给axios带上请求头:Authorization, 值为token值
config.headers.Authorization = window.sessionStorage.getItem('glmtoken')
// 返回ajax全部东西,接着开始发送请求
return config
});
// 添加响应拦截器
http.interceptors.response.use(function (response) {
// 对响应数据做点什么
if(response.data.meta.msg = '无效token' && response.data.meta.status == 400){
Vue.prototype.$message.warning('请重新登录!')
Router.push('/login')
}else{
return response;
}
});
// 登录验证
http.login = (url,sendLogin)=>{
return http.post(url,sendLogin)
}
// 左侧菜单获取
http.menus = (url,sendLogin)=>{
return http.get(url,sendLogin)
}
axios
.get(`http://wthrcdn2.etouch.cn/weather_mini?city=${this.city}`)
.then(backData => {
// 成功的回调函数,参数是响应体
console.log(backData);
})
.catch(error => {
// 失败的回调函数(参数是返回的错误信息)
console.log('失败了!');
console.log(error);
})
.finally( ()=> {
// 这个一般不会用(了解)
// 不管成功还是失败,最终都会来调用这个
console.log('不管成功还是是失败,你都能看到我哦!');
} )
axios.get(url,{
params:{}, // 发送传递数据
headers: { Authorization: window.sessionStorage.getItem("glmtoken") }, // 发送请求头
})
重点 : axios传递什么类型数据,请求头的content-type就发送什么类型,关键在于node.js后台需要用不同的方式方式来接收这个数据!!!
// 前端 :
axios.post('/upload',{data:{name:"glm",age:18}}) // 默认是json格式,所以不需要传递请求头
.then(function(data){
console.log('上传成功');
})
// 后端express :
let express = require('express');
let bodyParser = require('body-parser') // 引入body-parser框架
let app = express() // 开启服务器
app.use(bodyParser.json()) // 设置中间件
app.post('/upload',function(req, res){
console.log(req.body); // 经过中间件层的处理就能够获取到数据
})
app.listen(3000,function(){ // 监听服务器
console.log('running!');
})
//前端 :
let fordata = new FormData($('form')[0])
fordata.append('name','龚利明')
// 发送ajax请求
axios.post('/upload',fordata)
.then(function(data){
console.log('上传成功');
})
//后端express :
let express = require('express');
let multer = require('multer');
let app = express()
// 设置multer
let upload = multer({
dest: './public/img'
})
// 接收post的formdata请求
app.post('/upload',upload.single('img'),function(req, res){
console.log(req.file);
console.log(req.body);
})
// 监听服务器
app.listen(3000,function(){
console.log('running!');
})
//前端
let params = new URLSearchParams();
params.append('key','d7c82ebd8b304abeacc73b366e42b9ed');
params.append('info','你好啊');
// 发送ajax请求
axios.post('/upload',params)
.then(function(data){
console.log('上传成功');
})
// 后端express
let express = require('express');
// 引入body-parser框架
let bodyParser = require('body-parser')
// 开启服务器
let app = express()
// 设置中间件
app.use(bodyParser.urlencoded({extended:false}))
app.post('/upload',function(req, res){
console.log(req.body);
})
// 监听服务器
app.listen(3000,function(){
console.log('running!');
})
在下面的vue-cli中有介绍
aixos默认不支持跨域, 在引入axios之后要设置一下
// 每次请求携带cookies信息
axios.defaults.withCredentials = true
知识点&&注意点
transition
来包裹transition
默认为span标签,需要用tag来赋值transition
为什么标签transition
中有name属性,来控制css六中状态的样式编写 name的值为多少,就是把v-enter等中的v替换掉系统默认的六个状态
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。v-enter-to
: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter
被移除),在过渡/动画完成之后移除。v-leave
: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。v-leave-to
: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave
被删除),在过渡/动画完成之后移除。使用
<style>
.glm-enter,
.glm-leave-to{
opacity : 0;
transform : translateX(45px)
}
.glm-enter-active,
.glm-leave-active{
transition : all 0.5s
}
</style>
<transition name="glm" tag="div">
<p> 你好 </p>
</transition>
// p标签的消失隐藏用transition来包裹
// name设定的值和上边的css类的前缀对应,不设置默认为v
//css :
// 1. 设置进出时候的效果
.glm-enter,.sweath-leave-to{
opacity: 0;
transform: translateX(100px)
}
// 2. 设置进去的时候的动画
.glm-enter-active{
transition: all 0.5s ease
}
// 3. 挨个设置不同的延时时间
.weather_list div li:nth-child(1){
transition-delay: 0.2s
}
.weather_list div li:nth-child(2){
transition-delay: 0.4s
}
.weather_list div li:nth-child(3){
transition-delay: 0.6s
}
.weather_list div li:nth-child(4){
transition-delay: 0.8s
}
.weather_list div li:nth-child(5){
transition-delay: 1s
}
// html :
{{ item }}
.sweath-enter-active{
animation: slideInDown 0.8s ease
}
.sweath-leave-active{
animation: slideInDown 0.8s ease reverse
}
<body>
// 子组件son1
<template id="son1">
<div ref="son111">
<button @click="getson1name()">我是son1的按钮</button>
<div>我是{{name}},我今年{{age}}岁了!</div>
</div>
</template>
// 父组件
<div id="app">
<button @click="getson1name()">获取名字</button>
<son1 ref="son1"></son1>
</div>
<script src="../js/vue.js"></script>
<script>
// 定义子组件模板对象
let son1 = {
template : '#son1',
data() {
return {
name : '龚利明',
age : 18
}
},
methods: { // 让子组件点击按钮执行下边代码
getson1name(){
console.log(this.$refs.son111); // 打印出当前子组件的dom原生对象
console.log(this.$refs.son1.name); // son1是父元素声明的ref,所以不能访问,会报错
}
},
}
// 父组件实例
let vm = new Vue({
el : "#app",
components:{
son1
},
methods: {
getson1name(){
console.log(this.$refs.son1); // 不能访问子组件内部的ref
console.log(this.$refs.son111.name); // 打印出子组件的vue实例对象
}
},
})
</script>
// 总结 : 一个组件只能访问当前组件的原生dom对象
模块化 : 是后端业务逻辑的拆分,目的是为了只能单一
组件化 : 根据前端UI来划分的,方便UI的重用
这里使用的是全局组件创建, 下边会使用局部组件创建方式
// 创建组件模板
let son = Vue.extend({
template : 'hello world!!
'
})
// 注册组件模板 (注册了才能使用)
Vue.component('son',son)
Vue.component('son',{
template : '你好!'
})
<template id="son">
<div>
你好!
</div>
</template>
Vue.component('son',{
template : '#son'
})
最终版本
<template id="son">
<div>
你好!
</div>
</template>
let obj = {
template : '#son'
}
Vue.component('son',obj)
局部组件注册
<template id="son">
<div>
你好!
</div>
</template>
let son = {
template : '#son'
}
new Vue({
el : '#app',
components : {
son : son ,
}
})
组件使用的注意事项
-
来替代大写字母 (反正不不用驼峰就好了)父组件
<router-view :downSearch="downSearch"></router-view>
子组件
props: ['downSearch'], 或者 props:{downSearch:String}
methods: {
getList(){
console.log(this.downSearch);
}
},
注意 : this.$emit的this指向当前子组件, 但是传递过来的函数内部的this还是指向父组件,简单的说就是父组件把自己的一个方法传递给子组件,但是还是在父组件的作用域内执行,父组件只不过是把开关给了子组件,子组件帮父组件开启这个函数,并且也可以把字句的属性作为形参传递给父组件
总结 : 反正都用props和ref就好了!!!
#
的好处#
英文(hash) 俗称哈希,锚点 <div id="app">
我是标题
<router-link to="/aaa">aaa</router-link>
<router-link to="/bbb">bbb</router-link>
<router-link to="/ccc">ccc</router-link>
<router-view></router-view>
</div>
当导入这个插件的时候,在window默认就有一个VueRouter的构造函数了
// 组件aaa
<template id="aaa">
<div>
aaaaa
div>
template>
// 组件bbb
<template id="bbb">
<div>
bbbbbb
div>
template>
// 组件模板ccc
<template id="ccc">
<div>
cccccc
div>
template>
// 定义对象组件模板
ccc = {
template : '#ccc'
}
let router = new VueRouter({
routes :[
{path : '/aaa', component : {template : '#aaa'}},
{path : '/bbb', component : {template : '#bbb'}},
{path : '/ccc', component : ccc}, // c-cli脚手架就是这么用的
{path : '/', redirect : '/aaa'}
]
})
let vm = new Vue({
el : 'app',
router : router
})
// 或者直接简写 : router : touter ==> router
<router-link class="bar-item" active-class="active" to="/result">搜索结果</router-link>
<router-link class="bar-item" active-class="active" to="/player">歌曲播放</router-link>
<router-link class="bar-item" active-class="active" to="/mv">mv</router-link>
<router-link class="bar-item" active-class="active" to="/comment">歌曲评论</router-link>
html :
<router-link :to="{name : 'news'}">aaa</router-link>
// 或者下边的
<router-link to="/login">aaa</router-link> // 必须是绝对路径
js:
let router = new VueRouter({
routes :[
{path : '/aaa',
name : 'news',
component : {template : '#aaa'}
},
]
})
this. r o u t e r . p u s h ( ) 或 者 t h i s . router.push() 或者 this. router.push()或者this.router.replace()
两者区别 : push能使用浏览器的前进后退, replace是直接替换掉最后一个,所以没有前进后退,使用方法是根据具体情况来使用,通常同级路由有replace,父子之间用push
有以下两种办法写在methods中 :
let router = new VueRouter({
routes :[
{path : '/news/:id',
name : 'news',
component : {template : '传递进来的参数id为 : {{$route.params.id}} '}
},
]
})
注意 : $route主要要用的两个参数就是 query 和 params 两者的传参性质不太一样.但是目的都是为了父组件向子组件传值.
直接在url上传参, query本来就是获取url的传参的方式
使用
<body>
<div id="app">
<h1>我是主界面</h1>
// 可以通过两种字符串拼接作为传参的方式
<router-link :to="'/login?id='+ id">去登陆</router-link>
<router-link :to="`/register?name=${name}`">去注册</router-link>
<router-view></router-view>
</div>
</body>
<script src="../js/vue.js"></script>
<script src="../js/vue-router-3.0.1.js"></script>
<script>
// 1. 定义一个子组件
let login = {
template : `我是登录
{{$route.query.id}}
`
}
let register = {
template : `我是注册
{{$route.query.name}}
`
}
// 2. 定义路由表
let router = new VueRouter({
routes : [
{path : '/login', component : login},
{path : '/register', component : register},
{path : '/', redirect : '/login'}
]
})
// 3. 创建父组件的vue实例
let vm = new Vue({
el : '#app',
data() {
return {
id : 20,
name : '龚利明'
}
},
// 3.1挂载路由
router
})
</script>
</html>
使用方法 : 看下边的例子说明
例子 :
<body>
<div id="app">
<h1>我是主界面</h1>
<router-link to="/login/123456/龚利明">去登陆</router-link>
<router-link to="/register">去注册</router-link>
<router-view></router-view>
</div>
</body>
<script src="../js/vue.js"></script>
<script src="../js/vue-router-3.0.1.js"></script>
<script>
// 1. 定义一个子组件
let login = {
template : `我是登录
{{$route.query.id}}
`
}
let register = {
template : `我是注册
{{$route.query.name}}
`
}
// 2. 定义路由表
let router = new VueRouter({
routes : [
{path : '/login/:id/:name', component : login},
{path : '/register', component : register},
{path : '/', redirect : '/login'}
]
})
// 3. 创建父组件的vue实例
let vm = new Vue({
el : '#app',
data() {
return {
id : 20,
name : '龚利明'
}
},
// 3.1挂载路由
router
})
</script>
</html>
import Vue from 'vue';
import VueRouter from 'vue-router';
// 引入包
import Home from '../pages/home/Home.vue'
import Hot from '../pages/home/children/Hot.vue'
import Good from '../pages/home/children/Food.vue'
import Girl from '../pages/home/children/girl.vue'
import Liming from '../pages/home/children/Liming.vue'
import Love from '../pages/home/children/Love.vue'
import Machine from '../pages/home/children/machine.vue'
import Many from '../pages/home/children/Many.vue'
import Neiyi from '../pages/home/children/Neiyi.vue'
import Shoose from '../pages/home/children/Shoose.vue'
import SmallGirl from '../pages/home/children/SmallGirl.vue'
import Wbaobao from '../pages/home/children/Wbaobao.vue'
import Xidada from '../pages/home/children/Xidada.vue'
import Chat from '../pages/chat/Chat.vue'
import Mine from '../pages/mine/Mine.vue'
import Recomment from '../pages/recomment/Recomment.vue'
import Search from '../pages/search/Search.vue'
// 注册路由
Vue.use(VueRouter);
export default new VueRouter({
routes : [
{path : '/home',component:Home,
children:[
{path:'hot',component:Hot},
{path:'good',component:Good},
{path:'girl',component:Girl},
{path:'liming',component:Liming},
{path:'love',component:Love},
{path:'machine',component:Machine},
{path:'many',component:Many},
{path:'neiyi',component:Neiyi},
{path:'shoose',component:Shoose},
{path:'smallGirl',component:SmallGirl},
{path:'wbaobao',component:Wbaobao},
{path:'xidada',component:Xidada},
{path:'',redirect:'hot'}, // 二级路由的redirect和path要注意
]
},
{path : '/chat',component:Chat},
{path : '/mine',component:Mine},
{path : '/recomment',component:Recomment},
{path : '/search',component:Search},
{path : '/',redirect:'/home'},
]
})
作用 : 网页有些路由界面必须要先登录才能加载,此时可以通过路由守卫来进行预处理,当登录后,允许跳转到相应界面,未登录,则跳转到登录界面…
一般都使用全局路由!!!
使用 :
import Vue from 'vue'
import VueRouter from 'vue-router'
import axios from 'axios'
Vue.use(VueRouter)
// 引入组件
import Main from '../views/main.vue'
import GoodsInfo from '../views/GoodsInfo.vue'
import Login from '../views/Login.vue'
import Vip from '../views/vip.vue'
let router = new VueRouter({
routes : [
{path:'/main',component:Main},
{path:'/goodsinfo',component:GoodsInfo},
{path:'/login',component:Login},
{path:'/vip',
component:Vip,
// 跳转到 '/vip'路由之前开启这个函数
beforeEnter(to,from,next){
// 发送请求,判断是否登录
axios.get('site/account/islogin')
.then(callback=>{
// 如果登录,则允许访问
if(callback.data.code == 'logined'){
console.log(callback.data.code);
next()
}
else{
// 没有登录,跳转到登录界面
router.push('/login')
}
})
}
},
{path:'/',redirect:'/main'},
]
})
export default router
全局守卫 : 让所有的路由跳转之前先判断是否登录
使用方法 :
import Vue from 'vue'
import VueRouter from 'vue-router';
import Login from '../views/login/Login.vue';
import Main from '../views/main/main.vue'
import User from '../views/main/children/user.vue'
Vue.use(VueRouter)
const Router = new VueRouter({
routes: [{
path: '/login',
component: Login
},
{
path: '/main',
component: Main,
// meta 记录main需要验证
meta: {
requiresAuth: true
},
children:[
{
path : '/users', component : User,
}
]
},
{
path: '/',
redirect: '/main'
}
]
})
// 全局路由守卫
Router.beforeEach((to, from, next) => {
// 判断跳转到的路由是否需要验证
if (to.meta.requiresAuth) {
// 判断是否有在存储的token信息
if (window.sessionStorage.getItem('glmtoken') != null) {
next()
} else {
// 没有token信息,跳转回登录页面
Vue.prototype.$message({
message: "请重新登录!",
type: "warning"
})
Router.push('/login')
}
} else {
// 不需要验证的路由,直接跳转到该路由
next()
}
})
export default Router
在一级路由最下边注册一个path 为*
, 并且component为自己设置的error界面
[外链图片转存失败(img-NaV9meLV-1569292941630)(/1564125937094.png)]
<template>
<div class="makeLove">
<h1>找不到服务器,404报错了哦!!!!!!h1>
div>
template>
<script>
script>
<style scoped lang="less">
.makeLove {
width: 100%;
height: 100%;
position: absolute;
z-index: 999999;
left: 0;
top: 0;
h1 {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
style>
路由文件
通过 * 来搞定
import Vue from 'vue';
import VueRouter from 'vue-router';
// 引入包
import Home from '../pages/home/Home.vue'
import Chat from '../pages/chat/Chat.vue'
import Mine from '../pages/mine/Mine.vue'
import Recomment from '../pages/recomment/Recomment.vue'
import Search from '../pages/search/Search.vue'
import Error1 from '../components/error/Error.vue'
// 注册路由
Vue.use(VueRouter);
export default new VueRouter({
routes : [
{path : '/home',component:Home},
{path : '/chat',component:Chat},
{path : '/mine',component:Mine},
{path : '/recomment',component:Recomment},
{path : '/search',component:Search},
{path : '/',redirect:'/home'},
// 通过 * 来搞定
{path : '*',component : Error1},
]
})
[外链图片转存失败(img-ucNMDUeg-1569292941630)(/1563615247820.png)]
进去到下边这个界面 : 空格是选中,
[外链图片转存失败(img-xvoyN3b7-1569292941631)(/1563615445145.png)]
接着进入各种默认选择, 我选less 其它的选择还不怎么懂。 跳过跳过!
[外链图片转存失败(img-xP6xDLgy-1569292941632)(/…/…/…/…/…/AppData/Roaming/Typora/typora-user-images/1563615572895.png)]
最后安装就好了
-
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
}
]
})
#app
替换掉 ---------结合生命周期来理解import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
<template>
<div id="app">
<div class="tab-wrapper">
<!-- tab栏 -->
<div class="tab-bar">
<router-link class="bar-item" active-class="active" to="/result">搜索结果</router-link>
<router-link class="bar-item" active-class="active" to="/player">歌曲播放</router-link>
<router-link class="bar-item" active-class="active" to="/video">mv</router-link>
<router-link class="bar-item" active-class="active" to="/comment">歌曲评论</router-link>
</div>
<!-- 对应的内容区域 -->
<div class="tab-content" @click="getAxios()">
<router-view></router-view>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
methods: {
getAxios(){
}
},
}
</script>
<style scoped lang="less">
@import url('./assets/css/comment.css');
</style>
使用方法一 :
下载包 : npm i axios -D
把aixos注册到vue构造函数的原型上
import Vue from 'vue';
import axios from 'axios'
Vue.prototype.axios = axios;
在组件对象中使用需要使用this,因为组件对象的是由Vue构造函数创建的,通过原型链可以访问到Vue构造函数的原型对象上的方法
使用方法二 :
下载包 :
npm i axios -D
npm i vue-axios -D
use作用起来
import Vue from 'vue';
import axios from 'axios';
import VueAxios from 'vue-axios';
Vue.use(VueAxios,axios)
如此, 可以了把axios对象添加到Vue实例的原型上
作用 : 将数据存储在一个地方,方便任何的子组件来操作这些数据.直接通过一些vuex的API就可以操作
[外链图片转存失败(img-iIrtbgG1-1569292941633)(/1563702212403.png)]
手动配置 vue.config.js文件,这个文件需要自己在根目录下创建
// vue.config.js
module.exports = {
// 打包的根路径 使用的是相对
publicPath:'./',
// 移除map文件
productionSourceMap:false,
}
作用 :
[外链图片转存失败(img-g0FavIyJ-1569292941633)(/1564988895067.png)]
作用 : 把npm下载的vue / element-ui / aixos等框架通过cdn网络的形式导入,打包的时候就不用打包自己npm下载的这些库了, 大大减少了压缩后的文件大小.
使用 :
配置vue.config.js文件
// vue.config.js
module.exports = {
// 打包的根路径 使用的是相对
publicPath:'./',
// 移除map文件
productionSourceMap:false,
// 和import Vue from 'vue' 中的Vue要对上号,但是element例外
externals: {
'vue':'Vue',
'vue-router':"VueRouter",
'axios':'Axios',
'element-ui':"ELEMENT"
}
}
网络第三方库查找
cdn介绍:
[外链图片转存失败(img-HPhlrsFi-1569292941633)(/1564989748634.png)]
[外链图片转存失败(img-AoA4ZRi0-1569292941634)(/1563873186960.png)]
scoped : 当子组件设置了scoped, 父子组件相同的类设置了同一个样式, 当有冲突,最后加载的样式以子组件为主. 父组件新增的样式,要满足子组件没有设置,就可以作用了, 因此,当调用第三方组件,想对样式修改,是不能直接作用上去的. 必须通过/deep/来深度设置, 那么就可以覆盖掉子组件原本设置的样式了.
安装
npm install moment --save
引入和使用
在main.js中 导入组件
import moment from 'moment'
Vue.filter('FormateTime', function(dataStr, pattern = 'YYYY-MM-DD') {
return moment(dataStr).format(pattern)
})
vue create my-app
cd my-app
vue add element
引入和设置参数(全局或者按需引入)
2.1 全局
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css;
Vue.use(ElementUI);
2.2 按需引入
import Vue from 'vue';
import { Button, Select } from 'element-ui';
Vue.use(Button)
Vue.use(Select)
// 设置 babel.config.js
{
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
[外链图片转存失败(img-THrZg2o7-1569292941634)(/1563793440542.png)]
html :
el-pagination>
small : // 小一点
注意 : 1. prop=“name” 和 v-model=“ruleForm.name” 在data中名字要一样
推荐方法 : { pattern:/^1[3456789]\d{9}$/, message: '请输入正确手机号码', trigger: 'blur' }
官网没有 pattern 这个属性, 我是在百度查到的,反正可以用, 直接在pattern 里边写正则
复杂点的 : { validator: checkPhone, trigger: 'blur'}
validator可以绑定自定义的方法来验证, 具体看下边例子。 反正我觉得没上边的简单
<template>
<div class="login">
<div class="login_main">
<h2>利明后台管理登录</h2>
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm" label-position="top">
<el-form-item label="账号" prop="name">
<el-input type="text" v-model="ruleForm.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="ruleForm.password" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')" class="login_btn">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
data() {
var checkPhone = (rule, value, callback) => {
if (!(/^1[3456789]\d{9}$/.test(value))) {
return callback(new Error('输入正确的手机号码'));
}
};
return {
ruleForm: {
name: '',
password: '',
},
rules: {
name: [
{ required: true, message: '请输入账号', trigger: 'blur' },
{ validator: checkPhone, trigger: 'blur'},
{ pattern:/^1[3456789]\d{9}$/, message: '请输入正确手机号码', trigger: 'blur' },
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
]
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 验证成功在这里发送ajax请求
} else {
console.log('error submit!!');
return false;
}
});
},
}
}
</script>
<style scoped lang="less">
.login{
width: 100%;
height: 100%;
background: rgb(50, 65, 82);
display: flex;
align-items: center;
justify-content: center;
.login_main{
h2{
display: flex;
align-items: center;
justify-content: center;
}
width: 580px;
height: 400px;
padding: 30px;
background: #fff;
border-radius: 8px;
box-sizing: border-box;
.login_btn{
width: 100%;
margin-top: 20px;
background: skyblue;
}
/deep/ label{
font-size: 18px;
}
/deep/ input{
height: 50px;
}
}
}
</style>
/deep/
锁定标签名字 input 或者 label直接修改项目排布
[外链图片转存失败(img-t9tVFnF8-1569292941635)(/1563875250020.png)]
问题一 : 自定义控制路由转化
[外链图片转存失败(img-ifUncfda-1569292941635)(/1563883682659.png)]
问题二 : body和html可以都设置宽高百分之百来撑开
问题一 : ly-tab插件的使用
很简单,进npm官网看 https://www.npmjs.com/package/ly-tab
下载包 npm i ly-tab -D
引入注册
import Vue from 'vue'
import LyTab from 'ly-tab'
Vue.use(LyTab)
使用
html :
<ly-tab
v-model="selectedId"
:items="items"
:options="options"
@change="setPath"
>
</ly-tab>
js
标签只要是数据异步请求获得的,然后要渲染到html中(多半是第三方组件),都要加上v-if 防止发生错误。。 例如在swiper中,通过v-for渲染的img,loop属性需要