Vue 指令
Vue 模板指令
{{数据}} // 插值
v-text='数据' // 带标签的数据不会解析
v-html='数据' // 会解析 html 标签的数据
v-if='表达式' // 判断真假,创建或删除; 可选 v-else-if/v-else
v-show='表达式' // 显示或隐藏
v-bind:属性名='数据' // 动态绑定属性
:属性名 // 动态绑定简写
:style // 数组动态更新,对象 {样式:值} 改变不会被检测
:class // 数组动态更新,对象 {类名:true} 改变不能被检测
// 对象解决方法 --> Vue.set(改变的对象数据,'新属性','值')
// 数组[下标]不能更新解决办法 --> Vue.set(改变的数组,'下标','值')或splice
js
v-on:事件='方法' // 绑定事件
@事件='方法' // 绑定事件简写
v-bind:[attribute] // 动态参数 2.6.0 +
v-on:[eventName] // 动态参数
v-for='' // 遍历 in/of 关键字, (item,i) in arr; (val,key,i) of obj;n in 9;
v-model='变量' // 表单双向绑定
// text --> 获取文本框的值;
// checkbox --> 单选返回 true/false,多选返回数组[每个复选的 value];
// radio --> 返回单选的 value 值
// select --> 单选值为选中的 value,多选为数组
js
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no">
html
vm.toggle === 'yes' // 当选中时
vm.toggle === 'no' // 当没有选中时
js
自定义指令
<input v-focus='{i}' type="text" v-model='i'>
Vue.directive('focus', function(el,obj){ // el 原生,obj 参数
console.log('元素被创建/更新都会被调用');
})
// 注册
Vue.directive('my-directive', {
bind: function () {}, // 创建/绑定
inserted: function () {}, // 插入
update: function () {}, // 更新
componentUpdated: function () {}, // 组件更新后
unbind: function () {} // 解绑
})
js
Vue 属性更新检测
数组更新检测
push、pop、shift、unshift、splice、sort、reverse
filter()、concat()、slice() 返回新数组替换旧数据
arr[i] = xx ---> Vue.set(数组,下标,新值) vm.$set(数组,下标,新值) vm.数组.splice(下标,1,新值)
arr.length = n ---> vm.数组.splice(新长度)
js
对象添加属性
// 全局set
Vue.set(改变的对象,添加的键,值)
// 实例set
实例.$set(改变的对象,添加的键,值)
// 多个属性
改变的对象 = Object.assign({},改变的对象,{对象1},{对象2}...)
// 后面的对象合并到第一个参数,并返回第一个参数的引用,再复制给改变的对象
// 第一个参数需要是新对象,如果是要改变的对象引用不会变
js
对象删除属性
Vue.delete(对象,'属性名')
实例.$delete(对象,'属性名')
js
this.$nextTick
数据被修改且渲染之后再调用next回调,并返回promise对象
this.$nextTick这个方法作用是当数据被修改后使用这个方法会回调获取更新后的dom再渲染出来
methods:{
testClick() {
this.content = '改变了的值'
this.$nextTick(() => {
// dom元素更新后执行,因此这里能正确打印更改之后的值
console.log(that.$refs.tar.innerText) // 改变了的值
})
}
}
js
Vue 生命周期
- beforeCreate:初始化之前
- created:初始化之后
- beforeMount:渲染之前
- mounted:渲染之后
- beforeUpdate:更新数据渲染页面之前
- updated:更新数据渲染页面之后
- beforeDestroy:销毁之前
- destroyed:销毁之后
- activated:被 keep-alive 缓存的组件激活时调用。服务器端渲染期间不被调用
- errorCaptured:发生错误时触发
Vue 事件
内联语句处理器
@事件=‘方法($event)’ // $event 将当前事件原生 event 传入
事件修饰符
- .self: 只触发自己的方法,子节点冒泡不触发
- .stop: 阻止冒泡
- .prevent: 阻止默认行为
- .passive: 不阻止默认行为,不能与prevent一起使用
- .once: 只执行一次
- .capture: 使用事件捕捉模式
- @click.prevent.self 会阻止所有的点击
- @click.self.prevent 只会阻止对元素自身的点击
- .native: 原生事件
按键修饰符
- .ascii码值:按下对应的键值触发
- .enter:回车
- .tab:table
- .delete:“删除”和“退格”键
- .esc:退出
- .space:空格
- .up:上
- .down:下
- .left:左
- .right:右
自定义按键修饰符别名
Vue.config.keyCodes.f1 = 112
js
使用 —> @keyup.f1
- .ctrl
- .alt
- .shift
- .meta:windows/mac 的 command 键
多个按键
@keyup.alt.67 // ctrl+c
@keyup.click.ctrl // Ctrl + 点击
// 如果同时加了其他的按键按下也会触发
js
- .exact精确的修饰符按下事件
click.ctrl.exact // 只按下 ctrl 才能触发,多余按下不能触发
click.exact // 不按下任何键才能触发
js
鼠标修饰符
- .left
- .right
- .middle
表单修饰符
- .lazy:value 改变且失焦才触发,在 change 事件中同步
- .number:将输入的值转为 number 类型
- .trim:过滤输入的首位空格
Vue computed 计算属性与 watch 监听
computed 计算属性
依赖 data 的数据改变,computed 就会刷新
{{调用不需要加()}}
data : {
a : 1 // a 改变,fn 会刷新
},
computed: {
fn(){
return this.a + 10;
}
}
js
getter,setter
计算属性默认只有 getter
computed: {
name: {
// getter
get: function () {},
// setter
set: function (newValue) {}
}
}
// name = 'a' getter会被调用
js
watch 侦听属性
data:{name:'name',obj:{...}},
watch:{
name (新值,旧值){},// 浅监听
// 深监听
obj:{
deep:true, // deep 打开深监听
immediate:true, // immediate 立即执行
handler(新值){} // handler 只有新值
}
}
js
name 发生改变时 watch 发生回调
Vue filter 过滤器
- 通过 | 竖线管道符 把前面的数据传入|右边的方法
- 局部注册 filters :{方法名(val){}}
- 全局注册 Vue.filter(‘方法名’,(val) = > {})
- golbal(‘参数’)传入的参数, 方法内golbal(val,参数){} 接收形参第一个参数为 | 前面的值,第二个开始才是传进来的参数
{{1+2 | fn1 | golbal('sss')}}
Vue.filter('golbal',(val,a) => val + a)// 全局注册
let vm = new Vue({
el:'#box',
filters:{
fn1 : (val) => val.toFixed(2) // 局部注册,可以多个
}
})
js
Vue transition 动画过渡
class类
-
显示 name 为自定义组件上 name
- name-enter:进入前
- name-enter-active:进入中
- name-enter:进入后
-
消失
- name-leave:消失前
- name-leave-active:消失中
- name-leave-to:消失后
<style>
.name-enter,.name-leave-to{
width: 0;
}
.name-enter-active,.name-leave-active{
transition: all .3s;
}
.name-enter-to,.name-leave{
width: 100px;
}
</style>
</head>
<body>
<div id="box">
<button @click='tog'>click</button>
<transition name='name'>
<div v-show='fg'></div>
</transition>
</div>
html
组件属性 attr-class
- enter-class:进入前
- enter-active-class:进入中
- enter-to-class:进入后
- leave-class:离开前
- leave-active-class:离开中
- leave-to-class:离开后
4.1.1 以上 animate.css,需要加 animate__animated 与 animate__ 动画名
<transition
enter-active-class="animate__animated animate__bounce"
leave-active-class="animate__animated animate__bounceOutRight">
\>
<div v-show='fg' class="animated"></div>
</transition>
html
多个元素过渡
<transition enter-active-class="animate__animated animate__fadeInRight"
leave-active-class="animate__animated animate__fadeOutUpBig">
<div v-if='isshow' key="1"></div>
<div v-else key="2"></div>
</transition>
html
列表过渡
tag 把外层包装为 ul 标签,默认是 span
<transition-group tag="ul"
enter-active-class="animate__animated animate__fadeInRight"
leave-active-class="animate__animated animate__fadeOutUpBig"
\>
<li v-for="(item,index) in items" :key="item.id" @click='del(index)'>
{{ item }}
</li>
</transition-group>
html
过渡模式
- 在 transtion 上添加属性 mode
- in-out: 新元素先进行过渡,完成之后当前元素过渡离开。(一般不用)
- out-in: 当前元素先进行过渡,完成之后新元素过渡进入。
Vue 组件通讯与插槽事件分发
// 全局组件 [注意] 必须在new Vue之前
Vue.component('组件名',{
template:`html模板`,
// data必须为函数
data() {
return {}
},
// 局部组件
components : {
组件名:{}
}
});
// 根组件
new Vue({el:'#app'});
js
父传子
- 接收的变量与父组件的变量名一致
- 对象写法验证支持的类型,Number,String,Boolean,Array,Object,Function,null(不限制数据类型)
props:[接收的变量]
props:{
接收的变量:限制接收的数据类型,
接收的变量:{
type : [Number, String], // 单个或多个
default : '默认值',
required : true, // 必填项
}
// 自定义校验器
接收的变量: {
validator(val){
return xxx
}
}
}
js
<nav1 :val='a'></nav1>
Vue.component('nav1',{
template:`<h1>{{val}}</h1>`,
props:['val'] //
})
let vm = new Vue({
el:'#app',
data : {
a : 1
},
})
js
子传父
- <子组件 @自定义事件=‘父组件事件’></子组件>
- 子组件 this.$emit(‘自定义事件’,传参,[可选多个参数])
<div id="box">
<!-- nn被子组件调用,ff为父组件方法 -->
<qj @nn='ff' :val='a'></qj>
</div>
<script>
Vue.component('qj',{
template : `<button @click=ff>click</button>`,
data() {
return { child : '子组件值' }
},
methods: {
ff(){ // 调用自定义事件
this.$emit('nn',this.child)
}
},
})
let vm = new Vue({
el:'#box',
methods: {
ff(n){
console.log(n);
}
}
})
</script>
html
组件通信
- let bus = new Vue(); new 一个空 vue 作为中间传递
- bus.$emit(‘自定义事件’,‘发送的值’) 发送数据
- bus.$on(‘自定义事件’,回调函数) 接收数据
- [注意] 脚手架需要在 main.js 中 Vue实例之前在 Vue.prototype 属性添加 new Vue()
let bus = new Vue();
Vue.component('c1',{
template:`<div><button @click='fn1()'>click</button></div>`,
methods: {
fn1(){
bus.$emit('msg','值')
}
},
})
Vue.component('a2',{
template : `<div></div>`,
mounted() {
bus.$on('msg',d => { console.log(d); })
},
})
js
单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定,父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop 将其作为一个本地的 prop 数据来使用
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
js
ref 通信
- <组件 ref=‘自定义组件名字’></组件>
- 父组件操控:this.$refs.自定义组件名字 拿到实例
<slide ref='child'></slide>
Vue.component('slide',{
template : '<div></div>',
methods: {fn(){}}
})
let vm = new Vue({
el:'#box',
methods: {
getChild(){
console.log(this.$refs.child); // 拿到子组件的实例对象
this.$refs.child.fn()
}
}
})
组件使用 v-model
- props 接收父级数据,组件使用 $emit(‘input’,$event.target.value)发送
- [原理] v-model 等价 :value=p 和 @input ;$emit 调用 @input,发送当前 value
<child v-model='p'></child>
Vue.component('child',{
template : `<input :value='p' @input='$emit("input",$event.target.value)'>`,
props : ['p']
})
html
动态组件
- 使用 component 标签,绑定 is 属性,对应的值为组件名称
- 外层添加 keep-alive 可以在切换之后避免重新渲染元素
<keep-alive> <!-- keep-alive 可以避免动态组件重新渲染,每次切换不会删除之前的 -->
<!-- 改变 is 属性,is 的属性为组件的名字。每次切换组件后会重新渲染 -->
<component :is='who'></component> component会被替换为who组件的标签
</keep-alive>
html
slot插槽
- 插槽显示顺序以子组件的
为准 - 匿名插槽对应匿名
- 具名插槽父组件属性 slot=‘名字’ 子组件
对应 - 多个标签使用 template 标签并加上 slot='名字’属性。简写 #名字
- 作用域插槽,子组件动态绑定属性 :键=‘值’,name='名字’对应 父组件 #名字=‘接收参数’。接收的参数为对象,对象中包含子组件传入的键和值
父组件
<ss>
<mark>匿名插槽</mark>
<p slot="top">具名插槽</p>
<!-- 老语法 slot='' 新语法 #xxx 只能在template使用 -->
<template #bom>
<div>多个标签</div>
<p>多个标签</p>
</template>
<template #list='props'>
<div>{{props.objkey}}</div>
</template>
</ss>
html
子组件
<div>
<slot name="default"></slot>
<!-- 匿名插槽默认default -->
<slot name='top'></slot>
<slot name='bom'></slot>
<!-- 遍历数组,传出对象 {objkey:item,...} -->
<slot v-for="item of arr" :objkey='item' name="list"></slot>
</div>
html
VueCli 脚手架
安装创建
- cnpm i @vue/cli -g 安装新版
- cnpm I @vue/cli-init -g 安装旧版
- npm r vue-cli 卸载旧版
- where vue 查看老版本位置
- vue -V 查看安装版本
- vue init webpack 项目名 老版本创建项目
- vue create 项目名 — 选择vue 2或3的语法
Project description A Vue.js project 项目描述
Author tomiaa <1178852449@qq.com> 邮箱
Vue build (Use arrow keys)
Vue build standalone 独立生产环境
Install vue-router? Yes 安装路由
Use ESLint to lint your code? No 代码规范
Set up unit tests No 是否单元测试
Setup e2e tests with Nightwatch? No 测试
Should we run `npm install` for you after the project has been created? (recommended) npm 下载方式
sh
全局使用包
需要在 main.js 在 Vue 的原型上添加
import Vue from 'vue'
import $ from 'jquery';
Vue.prototype.bus = new Vue();
Vue.prototype.$ = $;
js
Vue router 路由
npm install vue-router -S
sh
router/index.js
// 引入依赖
import Vue from 'vue'
import Router from 'vue-router'
// 导出实例
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld/',
component: HelloWorld
}
]}
)
js
main.js
import App from './App'
import router from './router' // 引入 router
new Vue({
el: '#app',
router, // 添加
components: { App },
template: '<App/>'
})
js
App.js
添加 router 视口
<router-view />
html
路由原理
路由原理:
- hash路由 ==> location.hash 切换
window.onhashchange 监听路径的切换 - history路由==> history.pushState 切换
window.onpopstate 监听路径的切换
路由表
Vue.use(Router)
new Router({
mode : 'history', // history模式
base : 'vue', // 路由前缀 访问时地址自动添加base
routes: [
{
path: '/',
name: 'HelloWorld', // 路由命名
components:{ // 视图命名
default : HelloWorld,
a : topbar,
b : shopcar
},
meta : { // 元信息
title :'HelloWorld'
},
alias : '/biemin', // 别名 访问/biemin会跳转到 path路径
// 嵌套路由
children: [{
path: 'bar',
component: Bar,
meta: { requiresAuth: true }
}]
}]
})
js
视图命名
<router-view /> 没有name默认default
<router-view name="a"></router-view>
<router-view name="b"></router-view>
components:{ // 视图命名
default : HelloWorld,
a : topbar,
b : shopcar
}
html
重定向
// 第一种处理404
{
path : '',
component : notFound
},
// 第二种404处理 重定向
{
path : '',
redirect : '/notFound'
},
// 上面没有匹配到 进入 再进入notFound
{
path:'/notFound',
component : notFound
}
js
声明式导航
- 默认渲染为a标签,tag设置渲染标签类型
- to属性路由地址,可以是字符串,变量,对象{path:‘地址’},{name:‘命名路由’}(需要与router中name一致)
- 匹配的标签calss默认增加 router-link-exact-active完全匹配 与 router-link-active 局部匹配 [ / 也会匹配 ]
- to=‘/’ 会在其他路由中匹配,所以也会加上 router-link-active
- active-class=“类名” 属性 自定义类名
- replace 替换历史记录,点击后没有历史记录
<router-link to="/" tag="span" replace>Go to home</router-link>
<router-link to="/topbar" active-class="activeBar">Go to topbar</router-link>
<router-link to="/shop" active-class="activeBar">Go to shopcar</router-link>
<router-link :to="{path : '/shop'}" >Go to shopcar</router-link>
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view />
html
query 传参会显示在地址栏,刷新不会丢失。
params 传参需要用 name,且刷新会丢失。params 传参也可以使用动态路由显示在地址栏,如在 Router 表中定义 path: ‘/home/:id’
命名路由:
<router-link :to="{name : 's'}" >Go to shopcar</router-link>
new Router({
routes: [{
path: '/shop',
name: 's',
component: s
}]
})
js
编程式导航
replace 方法与 push 一样,但不会留下历史记录
router.push('home')// 字符串
router.push({ path: 'home' })// 对象
router.push({ name: 'user', params: { userId: '123' }})// 命名的路由
router.push({ path: 'register', query: { plan: 'private' }})// 带查询参数,变成 /register?plan=private
router.go(n) // 历史记录不够用则失败
router.go(1)// 在浏览器记录中前进一步,等同于 history.forward()
router.go(-1)// 后退一步记录,等同于 history.back()
router.go(3)// 前进 3 步记录
router.go(n)// 执行浏览器的前进动作,n代表前进的步数,负数代表后退
router.back()// 执行浏览器的后退动作
router.forward()
js
重复导航当前路径报错问题
在 Router 暴露之前重写 push 方法
const routerPush = Router.prototype.push;
Router.prototype.push = function push(location) {
return routerPush.call(this, location).catch(error=> error)
}
js
动态路由
- /detail/:变量名 设计路由
- 新页面 $route.params 接参 只有动态路由才有 params
- $route.query 是 ? 后面的参数,每个页面都可以有 不需要改动路由表
<router-link to="/detail/cansu "></router-link>
html
路由设计
{
path : '/detail/:name',
component : detail
}
js
解决首屏加载慢的问题
import shopcar from '@/components/shopcar'
import notFound from '@/components/notFound'
// 改为
const HelloWorld = () => import('@/components/HelloWorld')
const topbar = () => import('@/components/topbar')
js
路由守卫
- to – 要跳转到新的路由 router 对象
- from – 跳转之前的路由 router 对象
- next – 执行后续的中间件
- next(false) 中间当前的导航,并跳转到 from 对应的地址
- next(‘/地址’) / next({path:‘/地址’}) 跳转到指定的路径
全局守卫 – 写在 router 全局
router.beforeEach((to,from,next) => {}) // 进入之前
router.afterEach((to,from) => {}) // 离开之前
js
路由守卫 – 写在路由表
beforeEnter: (to, from, next) => {}
js
组件守卫 – 写在组件内
beforeRouteEnter(to, from, next) {
// 该组件对应的路由被确认之前调用
// 不能使用 this,实例还未被创建
}
beforeRouteUpdata(to, from, next) {
// 路由被改变,组件被复用时,可以访问 this
}
beforeRouteLeave (to, from, next) {
// 离开该组件对应的路由 可以调用 this
}
js
嵌套路由
{
path: '/topbar',
component: topbar,
meta : {title :'topbar'},
redirect : '/topbar/child1', // 打开 topbar 即重定向到 child1
children : [ // path 开头不带 / 为从上一层 /topbar 链接的地址 ---> /topbar/child1。带/需要路径补充完整
{path : 'child1',component:child1},
{path : 'child2',component:child2},
{path : 'child3',component:child3},
]
}
js
Vuex 状态管理
- state:储存状态
- getters:获取状态
- 两个参数: state 状态,getter 本身 调用方法传入参数可以使用闭包
- mutation:修改状态 – 方法名应单独使用文件定义为产量
- 两个参数: state 状态, commit 提交的参数
- 通过commit提交修改 commit(‘修改状态的方法’,参数) 必须为同步操作,异步需要在 action 中进行后 context.commit 提交
- commit:参数为对象时提交 payload 为 commit 的对象
- store.commit({ type: ‘increment’, amount: 10 }) - increment (state, payload) { state.count += payload.amount }
- action:异步操作
- $store.dispatch(‘调用action方法’,参数)
- 一个参数:context 指向 $store —> 使用 context.commit 提交修改
- 使用 {commit} 接参就是 context 内的提交方法
- modules:模块
- 模块定义 state 状态 获取属性 $store.state.模块名.属性
- getters 三个参数: state 状态,getter 本身,rootState 根的状态
- action 内 context 对应的是当前模块的上下文,包含 context.rootGetter为根的方法,rootState 根的状态
辅助函数
- mapState, mapGetters 写在 computed 里面, mapMutations,mapActions 则是在 methods 方法内
- [函数名/属性名] 映射相同名字或方法 修改名字需要{}形式 ,key为键,值为对应的方法
- 调用辅助函数返回对象,…展开后可以添加其他方法
- 返回的数据只是作为映射,方法/计算属性需要传参需要调用(传参)
引入
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
computed : {
...mapGetters(['ride']),
...mapState({
arrNum : 'num',
})
},
methods: {
...mapMutations({ square:SQUARE}),// 修改名字为square映射
...mapActions( {addnum:ADDNUM}),
}
js
传参
{{ride(3)}}
<button @click="addnum(3)">mapAction</button>
html
命名空间
模块 namespaced 开启
modules: {
aa : {
namespaced : true // 开启命名空间
}
}
js
第一种
import {createNamespacedHelpers} from 'vuex'; // 引入
const {mapState} = createNamespacedHelpers('命名空间名') // 创建
computed : {
...mapState['状态名']
}
js
第二种
import {mapState} from 'vuex';
computed : {
...mapState['命名空间名',['状态名']]
}
js
Vue 跨域代理
代理配置
2.0
proxyTable: {
'/api': {
target: 'http:// 127.0.0.1:3000/api', // 接口的域名
// secure: false, // 如果是https接口,需要配置这个参数
changeOrigin: true, // 如果接口跨域,需要进行这个参数配置,为true的话,请求的header将会设置为匹配目标服务器的规则(Access-Control-Allow-Origin)
pathRewrite: {
'^/api': '' // 本身的接口地址没有 '/api' 这种通用前缀,所以要rewrite,如果本身有则去掉
}
}
}
js
3.0
// vue.config.js 脚手架的配置文件
module.exports = {
// 选项...
// 配置跨域
devServer: {
proxy: {
'/api': {
target: 'http:// localhost:3000// api', // 接口的域名
// secure: false, // 如果是 https 接口,需要配置这个参数
changeOrigin: true, // 如果接口跨域,需要进行这个参数配置,为 true 的话,请求的 header 将会设置为匹配目标服务器的规则(Access-Control-Allow-Origin)
pathRewrite: {
'^/api': '' // 本身的接口地址没有 '/api' 这种通用前缀,所以要rewrite,如果本身有则去掉
}
}
}
}
}
js
配置 baseUrl
// 与axios同级 axios 引入 {api_url}
// ================== 区分环境,配置接口地址
let host, api_url;
if (process.env.NODE_ENV == "development") { // 开发环境
host = "http:// localhost:3000",
// api_url = "http:// localhost:3000/api"
api_url = "/api"
}
if (process.env.NODE_ENV == "production") { // 生产环境
host = "http:// localhost:3000",
api_url = "http:// localhost:3000/api"
}
export let HOST = host;
export let API_URL = api_url;
js
Vue Node.js 服务端渲染
依赖
"dependencies": {
"express": "^4.17.1",
"vue": "^2.6.12",
"vue-server-renderer": "^2.6.12"
}
json
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{{{meta}}}
<title>{{title}}</title>
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
html
app.js
const Vue = require('vue');
const server = require('express')()
const fs = require('fs')
const renderer = require('vue-server-renderer').createRenderer({
// 读文件,返回给浏览器去显示
template: fs.readFileSync('./index.html', 'utf-8')
})
// 页面的 head 部分
const context = {
title: 'vue-ssr-demo-title',
meta:
`<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
`
}
server.get('/huaweip40', (req, res) => {
const vm = new Vue({
data: {
url: req.url,
msg: 'huaweip40',
hobby: ['唱','跳','rap','打篮球']
},
template:
`<div>
<p>当前页面地址:{{url}}</p>
<p>{{msg}}</p>
</div>
`
})
renderer.renderToString(vm, context, (err, html) => {
// 失败的回调
if(err) {
res.status(500).end('err', err)
return
}
// 服务器给浏览器发送的数据
res.end(html)
})
})
server.get('/mi11', (req, res) => {
const vm = new Vue({
data: {
url: req.url,
msg: 'mi11',
hobby: ['唱','跳','rap','打篮球']
},
template:
`<div>
<p>当前页面地址:{{url}}</p>
<p>{{msg}}</p>
</div>
`
})
renderer.renderToString(vm, context, (err, html) => {
// 失败的回调
if(err) {
res.status(500).end('err', err)
return
}
// 服务器给浏览器发送的数据
res.end(html)
})
})
const port = 8082
server.listen(port, ()=> {
console.log('ok!!!!!!', port);
})
js
nuxt 基础使用
安装
npx create-nuxt-app <项目名>
js
目录结构
└─my-nuxt-demo
├─.nuxt // Nuxt自动生成,临时的用于编辑的文件,build
├─assets // 用于组织未编译的静态资源如LESS、SASS或JavaScript,对于不需要通过 Webpack 处理的静态资源文件,可以放置在 static 目录中
├─components // 用于自己编写的Vue组件,比如日历组件、分页组件
├─layouts // 布局目录,用于组织应用的布局组件,不可更改⭐
├─middleware // 用于存放中间件
├─node_modules
├─pages // 用于组织应用的路由及视图,Nuxt.js根据该目录结构自动生成对应的路由配置,文件名不可更改⭐
├─plugins // 用于组织那些需要在 根vue.js应用 实例化之前需要运行的 Javascript 插件。
├─static // 用于存放应用的静态文件,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。 服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下。文件夹名不可更改。⭐
└─store // 用于组织应用的Vuex 状态管理。文件夹名不可更改。⭐
├─.editorconfig // 开发工具格式配置
├─.eslintrc.js // ESLint的配置文件,用于检查代码格式
├─.gitignore // 配置git忽略文件
├─nuxt.config.js // 用于组织Nuxt.js 应用的个性化配置,以便覆盖默认配置。文件名不可更改。⭐
├─package-lock.json // npm自动生成,用于帮助package的统一设置的,yarn也有相同的操作
├─package.json // npm 包管理配置文件
├─README.md
shell
页面及路由
└─pages
├─index.vue
└─user
├─index.vue
├─one.vue
shell
nuxt会自动生成路由, 访问/是pages下的index.vue 访问/user是user下的index.vue 访问/user/one 也是
页面跳转
不要写a链接,因为是重新获取一个新的页面,而不是SPA
<nuxt-link to="/users"></nuxt-link> 声明导航
this.$router.push('/users') 编程导航
html
动态路由
需要创建对应的以下划线作为前缀的 Vue 文件 或 目录。
验证动态路由参数, 返回 true 表示通过,false 会跳转到 404 页面
export default {
validate(data) {
cosole.log(data)
return true
}
}
js
异步请求
export default {
async asyncData({ params, $http }) {
const post = await $http.$get(`https://api.nuxtjs.dev/posts/${params.id}`)
return { post }
}
}
js
asyncData 在服务端发送请求不存在跨域
因为 created 会触发两次,mounted 只会在浏览器触发一次
自定义路由
nuxt.config.js
router: {
extendRoutes(routes) {
routes.push({
path: '/',
redirect: '/center'
})
}
}
js