vue已经成了前端最热门的框架之一。在项目用的就是vue框架做开发,一直没有对vue总结,现在对vue进行一下总结。
一、vue常用指令
vue中带v-xxx 都是指令
v-html: 给元素的innerHTML 赋值,当值有标签时不显示标签。
v-text:给元素当innerText赋值,当值有标签时会展示出标签
v-if:判断是否显示,如果值为false,页面会展示
作为标记,如果变成true的时候往进插值
v-else:和else作用一样
v-else-if:和else if 作用一样
v-if家族是对元素的插入和移除的操作
v-show:是对元素显示隐藏做操作
二、v-bind使用
vue中给属性赋值使用v-bind:给元素的属性赋值。
可以给元素自带的属性赋值如value class src等等
也可以给自定义属性赋值
语法:v-bind:value=‘常量 || 变量名’、v-bind:class、v-bind:src等
简写::value=‘变量名’
<h3 v-bin:class="{add:变量名}"></h3>
三、v-on 使用
vue中所有的事件都是通过v-on来绑定。
v-on:click、v-on:scroll 等所有的原生事件。
也可以操作变量。
语法:v-on:click=“事件处理函数”
简写::click=“事件处理函数”
<button :click="事件处理函数"></button>
// 或者
<button v-on:click="事件处理函数"></button>
// 操作变量
<button :click="isShow = false"></button>
事件修饰符:
原生js可以用下面来阻止事件冒泡
1.event.stopPropagation();
2.return false;
在vue中使用:click.stop=“事件函数”;可以阻止事件冒泡
原生js取消事件默认行为
event.preventDefault()
vue中可以用:click.prevent=“事件函数”.
修饰符:self capture stop prevent的使用:
<div id="demo">
<!--第一种情况-->
<!--<div @click="divEven" style="border:1px #188eee solid;">-->
<!--<a href="www.baidu.com" @click="aEven">百度链接</a>-->
<!--</div>-->
<!--stop的使用:阻止事件冒泡的发生-->
<!--<div @click="divEven" style="border:1px #188eee solid;">-->
<!--<a href="www.baidu.com" @click.stop="aEven">百度链接</a>-->
<!--</div>-->
<!--prevent的使用:阻止默认事件的发生-->
<!--<div @click="divEven" style="border:1px #188eee solid;">-->
<!--<a href="www.baidu.com" @click.stop.prevent="aEven">百度链接</a>-->
<!--</div>-->
<!--self的使用:只有点击他本身时才去执行,点击他的子元素不去执行-->
<!--<div @click.self="divEven" style="border:1px #188eee solid;">-->
<!--<a href="www.baidu.com" @click.prevent="aEven">百度链接</a>-->
<!--</div>-->
<!--capture的使用:触发捕获事件()先执行大盒子的事件,起执行小盒子的事件-->
<div @click.capture="divEven" style="border:1px #188eee solid;">
<a href="www.baidu.com" @click.prevent="aEven">百度链接</a>
</div>
</div>
还有很多不常用的事件修饰符。这里就不一一列举了;可以到Vue 官网事件处理查看
点击此处查看Vue 事件处理
四、v-model
用在表单元素上
v-model主要用于数据双向绑定;
页面改变影响内存(js);
内存改变影响页面(js);
v-bind和v-model的区别:
v-bind:可以给任何属性赋值,是从vue到页面的单向数据流。
v-model只给具备value的属性的元素进行双向数据绑定(必须使用的是有value属性元素);
五、v-for使用
基本语法:v-for=“item in arr”; 主要用于遍历数组和对象
对象的操作:v-for=“item in obj”;
如果有列表哟id可以不用写index,如果没有可以写成v-for="(item,index) in arr"
还有一个比较重要的一点 v-for尽量都写上:key,有id了些id,没有了写上index;
如下代码:
<ul>
<li v-fro="(item,index) in arr" :key="index"></li>
</ul>
v-for中为什么要加:key
查阅相关文档给出的解释如下:
vue和react的虚拟DOM的Diff算法大致相同,其核心是基于两个简单的假设。
首先讲一下diff算法的处理方法,对操作前后的dom树同一层的节点进行对比,一层一层对比,如下图:
当某一层有很多相同的节点时,也就是列表节点时,Diff算法的更新过程默认情况下也是遵循以上原则。
比如一下这个情况:
我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:
即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
vue中列表循环需加:key=“唯一标识” 唯一标识可以是item里面id index等,因为vue组件高度复用增加Key可以标识组件的唯一性,为了更好地区别各个组件 key的作用主要是为了高效的更新虚拟DOM.\。
六、父子组件传值
1、组件:
局部组件components
全局组件 Vue.component(‘组件名字’,{options})
组件传值:
父组件传值给子组件: 方法一、props,props是写在子组件中的
1、在父组件中绑定自定义属性
2、在子组件中使用props接收父组件传递的数据 3、可以在子组件中任意使用父组件数据
子组件传值给父组件
方法一、$ emit()
1、在父组件绑定自定义事件
2、子组件中出发原生的事件,在函数中使用$emit出发自定义事件
1、父用子时通过属性传递
2、子组件要声明props:[‘属性名’]来接收
3、接收到后就可以随便使用
七、单双向数据绑定
单向数据流绑定(vue -> html)
<input type="text" :value="text">
双向数据绑定(vue -> html -> vue)
<input type="text" v-model="text">
vue基本原理:数据发生改变,视图跟着发生改变,简言之数据驱动视图(vue的核心思想)
v-mode原理
v-model双向数据绑定的体现,只会体现在UI控件中,只能应用在有value的属性上,
v-model实际上就是语法糖,他的实际原理是v-bin:value和v-on:input的体现
八、slot:就是父组件传递给DOM结构
内置的组件
slot就是父组件传递给DOM留下的坑
<子组件>DOM</子组件>
slot是动态的DOM,props是动态的数据;
slot插槽:无名插槽和具名插槽
<slot name="two"></slot>
使用的时候 <h2 slot="two"></h2>
九、生命周期
vue生命周期
beforeCreate // 组件创建之前
created // 组件创建了
beforeMount // 组件挂载dom之前
mounted // 组件挂载dom
beforUpdate // 数据更新之前
updated // 数据更新
beforeDestroy // 组件销毁之前
destroyed // 组件销毁
activated // 组件被激活
deactivated // 组件被停用
errorCaptured // 捕获组件异常
errorHandler // 捕获全局异常
<keep-alive></keep-alive>
// vue内置组件,能将组件在切换的过程中将组件保存在内存中,防止重复渲染DOM,配合组件v-if 隐藏显示的时候使用。和生命周期activated和deactivated使用。
keep-alive两个属性:
include: 字符串或正则表达式。只有匹配的组件会被缓存。
exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。
例子:
<body>
<div id="app">
<App></App>
</div>
<script src="./node_modules//vue/dist/vue.min.js"></script>
<script>
Vue.component("Test",{
data(){
return{
msg:"hello world",
isShow:true
}
},
template:`
<div>
<h3>{{msg}}</h3>
</div>
`,
methods:{
},
beforeCreate(){ // 组件创建之前
console.log(this.msg)
},
created() { // 组件创建之后
console.log(this.msg)
// created方法可以操作后端的数据 数据驱动视图
},
beforeMount() {
// 将数据挂载在数据之前调用
console.log(document.getElementById("app"))
},
mounted() {
// 挂载数据到DOM之后调用,vue作用以后的Dom,操作dom
console.log(document.getElementById("app"))
},
beforeUpdate() {
// 在DOM更新数据之前调用,应用:可以获取原始Dom
console.log(document.getElementById("app").innerHTML)
},
updated() {
// 在DOM更新数据之后调用,应用:可以获取新的DOM
console.log(document.getElementById("app").innerHTML)
},
beforeDestroy() { // 组件销毁前
console.log("beforeDestroy")
},
destroyed() { // 组件销毁
console.log("destroyed")
},
activated() {
console.log("组件被激活了")
},
deactivated(){
console.log("组件被停用了")
}
});
var Header = {
data(){
return{
mas:"我是头部",
isShow:true
}
},
template:`
<div>
{{mas}}
<button @click="clickFun">点击</button>
</div>
`,
components:{
},
methods: {
clickFun(){
this.mas = this.mas + "测试";
}
},
};
var App = {
data(){
return{
isShow:true
}
},
template:`
<div class="app">
<Header/>
<keep-alive>
<Test v-if="isShow"/>
</keep-alive>
<button @click="changeg">显示隐藏</button>
</div>
`,
methods: {
changeg(){
this.isShow = !this.isShow;
}
},
components:{
Header,
},
};
var vm = new Vue({
el: '#app',
data() {
return {
}
},
methods: {
},
// template:`<app></app>`,
components:{
App,
}
})
</script>
</body>
十、vue中获取DOM
1、在template中任意Dom元素任意标签上写上ref=“xxxx”,
2、通过组件对象this.$refs.xxxx来获取dom元素
var Header = {
template:`
<div class="header" ref="header"> // ref = "xxxx"
<button @click="funCli">点击</button>
<input type="text" ref="input">
</div>
`,
methods: {
funCli(){
this.$refs.header.style.background="red"; // 通过this.$refs.xxxx获取上面的dom
}
},
mounted(){
this.$nextTick(function(){ // 真正等vue渲染dom后在操作的,可以放在this.$nextTick中执行
this. $refs.input.focus()
})
}
};
$属性: $refs获取组件内的元素,
$parent:获取当前组件对象的父组件
$children:获取子组件
$root:获取new Vue的实例 vm
$el: 组件对象的DOM元素
十一、路由
1、前端路由原理
做vue路由时候先来了解下前端路由:hash(哈希模式) 和 history模式
(1)、原生hash(哈希模式)
前端路由的原理是:锚点值做不同的显示,页面不跳转,加上innerHTML的替换,如下代码:
<body>
<a href="#/login">点我登录</a>
<a href="#/register">点我注册</a>
<div id="content"></div>
</body>
<script>
var oDiv = document.getElementById('content');
window.addEventListener('hashchange',() =>{
switch(location.hash){
case '#/login':
oDiv.innerHTML = "<h1>登录页面吧</h1>";
break;
case '#/register':
oDiv.innerHTML = "<h1>注册页面</h1>";
break;
}
})
</script>
(2)、history模式
如果不想看到#可以使用history模式,原理依赖于history.pushState函数
- a标签点击以后,如果没有#必然会页面跳转发起请求
- 使用pushState函数可以改变url 比如 /abc而不会 发起请求
- js通过location.pathname获取/abc做页面局部替换
下面是原生history模式的实现
// 01_history.html文件代码
<body>
<!--类似于router.link-->
<a href="javascript:void(0)" onclick="goHistory('/user')">去看User</a>
<a href="javascript:void(0)" onclick="goHistory('/goods')">去看goods</a>
<div id="box"></div>
<script type="text/javascript">
// 点击按钮时
function goHistory(url){
let text = '';
switch(url){
case '/user':
text = '用户页面'
break;
case '/goods':
text = '商品页面';
break;
}
// 判断后做相应url改变
history.pushState({},'',url);
// 改变页面效果
document.getElementById("box").innerHTML = text;
}
// 当页面加载的时候
// 处理刷新的时候
window.onload = function(){
let text2 = '';
let path = location.pathname;
switch(path){
case '/user':
text2 = '用户页面';
break;
case '/goods':
text2 = '商品页面';
break;
}
document.getElementById("box").innerHTML = text2
}
</script>
</body>
*********************************************************************************************
//01_server.js 服务端代码
const http = require('http');
const fs = require('fs');
http.createServer((req,res) => {
fs.readFile('./01_history.html',(err,data) => {
res.end(data)
})
})
.listen(8888);
*******************************************
需要在服务端启动看效果
node ./01_server.js
2、vue路由
《一》、步骤:
(1)、引入vue插件 vue-router.js
(2)、安装插件Vue.use(Vue.router);
(3)、创建一个路由对象
var router = new VueRouter({
(4)、配置路由对象
routes:[{
path:/login,component:Login}]})
(5) 、将配置好的路由对象关联到vue实例中
(6)、指定路由改变局部的位置
例子:
<body>
<div id="app"></div>
</body>
<script src="../node_modules/vue/dist/vue.min.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.min.js"></script>
<script>
var Login = {
template: `<div>我是登录页</div>`
};
var NewPage = {
template:`<div>我是新闻</div>`
};
// 2
Vue.use(VueRouter); // Vue.use(插件对象); 过程中会注册一些全局组件,及给vm或者组件对象挂在属性;
// 3
var router = new VueRouter({
// 4
routes:[
{name:'login',path:'/login',component: Login},
{ name:'news',path:'/newPage',component:NewPage},
{ path:'vue/:id', // params使用 name:'vue',component:VuePage },
]
})
// 6
var App = {
template: `
<div>
<router-link :to="{name:'login'}">登录页</router-link>
<router-link :to="{name:'news'}">新闻页</router-link>
<router-view></router-view>
</div>
`
};
// 5
var vm = new Vue({
el: '#app',
router:router,
components: {
app:App
},
template: `
<app/>
`,
})
</script>
《二》、 router-link
<router-link :to="{path:'路径'}" ></router-link>
<router-link :to="{name:'路径名'}" ></router-link>
router-link
Vue.prototype.xxx = {add:in}
所有组件中,使用this.xxx就能拿到这个对象
1、配置 :to="{name:'detail',query:{id:1}}" 或者 :to="{name:'detail',params:{id:1}}"
2、规则 {name:'detail',path:'/detail',component:Detail}
3、获取 this.$route.query.id
4、生成 <a href='/detail?id=1'></a>
path方式:
1、配置 :to="{name:'detail',params:{name:'abc'}}"
2、规则 {name:'detail',path:'/detail/:name'}
3、获取 this.$route.params.name
4、生成 <a href='/detail/1'></a>
命名路由:
1、给路由对象一个名字{name:“home”,path:’/home’,component:Home}
2、在router-link属性中描述这个规则:通过名称找路由对象,获取path,生成自己的href <router-link :to="{name:'home'}"></router-link>
3、优点降低维护成本,锚点值改变只用在main.js中改变path属性即可。
总结:
vue-router使用步骤:
1、引入vue-router.js
2、安装插件
3、创建路由实例
4、配置路由规则
5、将路由对象关联vue
6、留坑<router-view></router-view>
router-link :to=“xxx” 命名路由
1、在路由规则对象中加入name属性
2、在router-link中绑定对象 :to="{name:‘名字’}"
生僻API梳理:
1、 Vue.use(插件对象); 过程中会注册一些全局组件,及给vm或者组件对象挂在属性;
2、给vm及组件对象挂在的方式:
Object.defineProperty(Vue.prototype,'$router',{
get:function(){
return 自己的router对象;
}
})
vue-router中的对象:
$route 路由信息对象,只读对象; this.route.query.name
$router 路由操作对象,只写对象; this.router.push('/login')
路由嵌套实例:
<body>
<div id="app"></div>
<script src="../node_modules/vue/dist/vue.min.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.min.js"></script>
<script>
var WebPage = {
template:`
<div>前端学习页</div>
`
};
var ReactPage = {
template:`
<div>react学习页</div>
`
};
var HomePage = {
template:`<div>
我是首页
<hr/>
<router-link :to="{name:'webPage'}">前端总结</router-link>
<router-link :to="{name:'reactPage'}">React学习</router-link>
<router-view></router-view>
</div>`,
};
var NewsPage = {
template:`<div>我是新闻</div>`
};
var router = new VueRouter({
routes:[
{path:'/', redirect:'home'}, // redirect路由重定向
{path:'/home',component:HomePage,name:'home',
children:[ // 嵌套路由
{ path:'/',redirect: 'webPage'},
{path:'webPage', component:WebPage,name:'webPage'},
{path:'reactPage',component:ReactPage,name:'reactPage'}
]},
{path:'/news',component:NewsPage,name:'news'}
]
});
var App = {
template:`
<div>
<router-link :to="{name:'webPage'}">首页</router-link>
<router-link :to="{name:'news'}">新闻</router-link>
<router-view></router-view>
</div>
`,
components:{
HomePage
}
};
var vm = new Vue({
// el:'#app',
template:`<App/>`,
router,
components:{
App
}
}).$mount('#app')
</script>
</body>
路由参数实例:
<body>
<div id="app"></div>
<script src="../node_modules/vue/dist/vue.min.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.min.js"></script>
<script>
var VuePage = {
template:`<div>vuePage</div>`
};
var ReactPage = {
template: `<div>reactPage</div>`
};
var AngularPage = {
template: `<div>angularPage</div>`
};
var HomePage = {
template:`
<div>
我是首页
<br/>
<router-link :to="{name:'vue',params:{id:1}}">vue</router-link> // params参数使用
<router-link :to="{name:'react',query:{userId:1}}">react</router-link> // query参数使用
<router-link :to="{name:'angular'}">angular</router-link>
<router-view></router-view>
</div>
`
};
var NewsPage = {
template: `
<div>我是新闻</div>
`
};
var router = new VueRouter({
routes:[
{ path:'/', redirect:'home'},
{ path:'/home',name:'home',component:HomePage,
children:[
{path:'/',redirect:'vue'},
{path:'vue/:id', // params使用 name:'vue',component:VuePage},
{path: 'react', name: 'react',component: ReactPage},
{path:'angular',name:'angular',component:AngularPage}
] },
{ path:'/news', name:'news', component:NewsPage}
]
});
var App = {
template:`
<div>
<router-link :to="{name:'home'}">首页</router-link>
<router-link :to="{name:'news'}">新闻</router-link>
<router-view></router-view>
</div>
`
};
var vm = new Vue({
el:"#app",
data(){
return{
}
},
template:`<App>`,
router,
components:{
App
}
})
</script>
</body>
路由meta简单模拟拦截登录实例
知识点:
路由meta元数据 > meta是对于路由规则是否需要验证权限的配置
1、路由对象中和name属性同级{meat:{isChecked:true}}
路由钩子 > 权限控的函数执行时期
1、每次路由匹配,渲染组件到router-view之前
2、router.beforeEach(function(to,from,next){})
redirect里有重定向
<body>
<div id="app"></div>
<script src="../node_modules/vue/dist/vue.min.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.min.js"></script>
<script>
var isLogin = false;
var HomePage = {
template:`
<div>
我是登录页
</div>
`,
created() {
isLogin = true;
},
};
var NewsPage = {
template: `
<div>我是新闻</div>
`
};
var router = new VueRouter();
router.addRoutes([ // 这样的写法可以多次的追加路由规则,动态获取路由规则,更为灵活,可以方便调用后追加路由规则
// { path: '/', redirect: 'home' },
{ path: '/home', name: 'home', component: HomePage, },
// meta:{isChecked:true}给未来路由的权限权限控制,全局路由守卫来做参照条件
{ path: '/news', name: 'news', component: NewsPage, meta:{isChecked:true}}
]);
router.beforeEach(function(to,from,next){
console.log(to);
console.log(from)
if(to.meta.isChecked){
if(isLogin){
next(); // next(false) 取消用户导航行为
} else {
alert("请先登录");
next({name:'home'}); // 可以个对象也可以给锚点值
}
} else {
next(); // 不调用会卡住
}
});
var App = {
template:`
<div>
<router-link :to="{name:'home'}">登录</router-link>
<router-link :to="{name:'news'}">新闻</router-link>
<router-view></router-view>
</div>
`
};
var vm = new Vue({
el:"#app",
data(){
return{
}
},
template:`<App>`,
router,
components:{
App
}
})
</script>
</body>
后端路由的原理就是 url + 请求方式 后端判断(只做了解)
前端路由 url(锚点值)+ innerHTML
(2)、原生history模式
去除了#方式,每次都向服务器请求index.html,再由客户端分析当前url,做不同的变化。
实现原理:
1、在页面通过location.pathname获取当前请求url
2、让服务器不论什么请求都返回以上这个index.html
1、在页面通过location.pathname获取当前请求url
//HTML代码
switch(location.apthname){
case '/user':
document.body.innerHTML = '用户页面';
break;
case '/login':
document.body.innerHTML = '登录页面';
break;
default:
document.body.innerHTML = '我是history模式'
}
2、让服务器不论什么请求都返回以上这个index.html
// 前端服务器代码
const http = require('http');
const fs = require('fs');
let server = http.createServer();
server.on('request',(req,res) => {
fs.readFile('./index.html',(err,data) => {
res.end(data)
})
})
server.listen(8888);
vue History模式
import Vue from 'vue'
import Router from 'vue-router'
import wxEntrance from '@/wx.vue'
/*
import Home from '@/components/Home/Home';
import Member from '@/components/Member/Member';
*/
const home = r => require.ensure([], () => r(require('../components/Home/Home.vue')), 'home') //首页
const member = r => require.ensure([], () => r(require('../components/Member/Member.vue')), 'member'); // 会员
Vue.use(Router); // 注册全局组件 router-view router-link 挂在在Vue.prototype.$router || $route,未来所有的组件中的this对象,就具备该属性,所有的this就是vue的子类对象
export default new Router({
mode:'history', // 设置history路由模式
base:__dirname,
routes: [{
path: '/',
redirect: '/home',
component: wxEntrance,
children: [
{ path: '/', redirect:'/home' },
{ name:'home', path:'/home', component:home, meta:{ requireAuth: false}},
{ name:'member', path:'/member', component:member,meta:{ requireAuth: false}},、
]
},
],
scrollBehavior(to, from,savedPosition){ // 记录滚动的位置
console.log(to);
console.log(savedPosition);
return{
x:0,y:50 // return 期望滚动到那个位置
}
}
})
History模式可以设置页面滚动
十二、过滤器filter:全局过滤器和局部过滤器
1、局部过滤器:直接在局部组件中使用。
filters:{
// 声名过滤器
filteName:function(value){
return "$"+vvalue
}
}
2、全局过滤器 Vue.filter
Vue.filter("filterName",function(value){
return value.split('').reverse().join('')
})
十三、watch监听
watch监听的是单个属性
基本数据类型简单监听
复杂数据类型深度监听
例如:
var mag = '';
var arr = [{name:"jack"}]
Watch:{
mag:function(newV,oldV){ // 简单监听 newV新值 oldV旧值
console.log(newV,oldV)
},
arr:{ // 深度监听复杂类型arr数组
Deep:true,
handler:function(newV,oldV){
console.log(newV)
}
}
}
computed计算属性:
计算属性只有getter,
但是在适当的时候可以用setter
十四 axios
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
特性
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
模拟请求示例:
<body>
<div id="app"></div>
<script src="./vue.min.js"></script>
<script src="./vue-router.min.js"></script>
<script src="./axios.min.js"></script>
<script>
var App = {
template:`
<div>
<button @click="sendAjax">点击发送</button>
</div>
`,
components:{
},
methods: {
sendAjax(){
axios.get("http://127.0.0.1/:8080",{})
.then(res =>{
console.log(res)
})
.catch(err => {
console.log(err)
})
//***********************************************
// 配置公共请求数据连接(接口前面一样的,可以写成下面里面)
this.$axios.defaults.baseURL = "http://127.0.0.1/";
// ************************************************
// 合并多个请求,并处理其成功和失败
//var q1 = this.$axios.get('');
//var q2 = this.$axios.get('add','a=1');
//this.$axios.all([q1,q2])
//.then(this.$axios.spread((res1,res2)=>{
//}))
//.catch(err => {
//})
}
},
};
Vue.prototype.$axios = axios;
var vm = new Vue({
el:"#app",
data(){return{}},
template:`<app/>`,
components:{
App
}
})
</script>
</body>
十五、预渲染prerender(在spa进一步做了优化)
SPA搜索引擎优化(SEO)
1、安装插件:
npm install prerender-spa-plugin -D
2、配置webpack.prod.js文件
const PrerenderSpaPlugin = require("prerender-spa-plugin");
plugins:[
new PrerenderSpaPlugin({
staticDir:path.join(__dirname,'..','dist'),
routes:['/','/user'] // 根据这两个路由规则找到组件渲染HTML文件
})
]
3、配置路由变更对象,传递构造属性
mode:‘history’
4、构建项目代码 npm run build
5、进入dist目录 启动生成的代码 hs -o -p 999
十六、骨架屏(Sekeleton)
请求数据回来之前展示的效果,可以提前预览结构,类似于loading,
相当于loading图标,相比较loading图标而言,用户可以预览未来要看到的结构,同时避免了白屏的尴尬,还能操作,因此用户体验较好,当然这些是跟需求走,也有应用将loading结合骨架屏来实现的。
可以通过lavas插件来实现骨架屏: 点击查看lavas文档
操作步骤:
1、npm i -g lavas
2、lavas init
3、选择包含app_shell 也包含了骨架屏的功能
可以配置多个骨架屏
1、预渲染解决静态数据SEO
2、骨架屏,代替loading图标,用户体验更好,可以提前预览结构
如果配合上WPA中的service worker就可以缓存各种数据,不必要请求多余的资源(包括骨架屏资源)
service worker可以实现离线浏览(所有资源缓存在期中,拦截浏览器请求,相应保存的结果)
阶段总结:
1、路由懒加载的使用
2、通过router-view传递参数$refs 在要使用的子组件内props:[‘xxx’]
3、this.xxx.header使用
理解面试和沟通的
SPA是什么?
vue-router中是否可以不使用#来开发,使用history模式,默认是hash模式
在history模式下,可以scroll导航后滚动
history模式实现其实是基于服务器每次返回index.html而客户端根据location.pathname来做渲染。
SEO是什么,搜索引擎优化
SPA下SEO必然比较差的
使用预渲染,然后固定的页面,作为服务器响应的结果响应回来,也是基于history模式
vue 多页面应用:
核心思想:就是两个vue项目,一次webpack打包,关联url联系
webpack操作:
1、多个入口{main1:’./usermain.js’,main2:’./goodsmain.js’}
2、多个html插件
注意事项:
// 文件名称
filename:filename+’.html’
// 页面模版需要加对应的js脚本,如果不加这行则每个页面都会引入所有的js脚本
chunks:[‘manifest’,‘vendor’,filename]
getHtmls的思路
更为灵活的读取各项目下的js文件(入口)entry:{‘js文件名’:‘js文件路径’}
更为灵活的读取各项目下的html文件(首页.html)plugins:[].concat([new HtmlWebpackPlugin()]); 有几个 new 几个
filename属性是生成的相对dist的文件名xxx.html
template模版生成的参照物 需要绝对路径||相对路径’./xxx.html’
chunks:[filename]指定第三引入的js文件名称
PWA(渐进式/web/application)谷歌开发的
安装
vue init pwa 项目名称
hs -o -p 端口号
应用:
离线浏览web应用,生成桌面应用,顶部通知(页面都可以不存在),预缓存(在页面没有启动前,请求资源保存在浏览器)(真正访问的时候,非常快,请求本地),骨架屏,App shell(利用缓存机制保存html+css+js等)
服务器渲染(SSR)(插件vue-server-renderer)
什么是服务端渲染
vue.js是构建用户端应用程序的框架,默认情况下,可以在浏览器中输入vue组件,进行生产DOM和操作DOM。然而,特可以将同一个组件渲染为服务器端的HTML字符串,将他们直接发送到浏览器,最后将这些静态标记“激活”为客户端上完全可交互的应用程序。
(一)、简易的服务端渲染理解
简单的node.js服务器渲染demo
cd 到对应文件 => 运行 npm init --yes =>然后在运行npm in vue express vue-server-prenderer
在文件夹新建 server.js文件,输入如下代码:
const Vue = require('vue')
const express = require('express')()
// 创建服务端的渲染器
const renderer = require('vue-server-renderer').createRenderer()
// 创建vue实例
const app = new Vue({
template:'<div>hello 我是简单的服务端渲染页面</div>'
})
// 服务端渲染的核心就在于:通过vue-server-renderer插件的renderToString()方法,将Vue实例转换为字符串插入到html文件
express.get('/',(req,res) => {
renderer.renderToString(app,(err,html) => {
// console.log(html)
if(err){
return res.state(500).end("运行错误")
}
res.send(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue2.0 SSR渲染页面</title>
</head>
<body>
${html}
</body>
</html>
`)
})
})
// 服务端渲染
express.listen(8001,()=>{
console.log("服务端已启动")
})
命令行运行node ./server.js 启动项目
渲染结果如下: