1:vue是一套构建用户界面的渐进式框架, 特点:模块化,组件化:在vue中所有的都是组件,mvvm:双向数据绑定 适合做spa, var vm=new Vue({}) 一个vue实例有:挂载元素,数据,模版,方法,生命周期钩子 指令:v-text:绑定普通的文本,{{}}是简写方式 v-if,v-for,v-html:解析html字符串, 属性指令:<img src="{{}}" class与style绑定
1:vuex是一个状态管理,整个应用的状态放到vuex的store中, 提交mutations时改变状态的唯一方法,这个过程是同步的 异步逻辑应该封装到mutation中 vuex的状态存储是响应式的,当vue组件从store读取状态时,store中的状态发生变化,相应的组件也会得到更新,改变store中的状态的唯一途径是显式的提交,整个应用的状态放到vuex的store中, 路由:定义路由组件,const foo={template:'
在子组件 child.vue 中的 props 选项中声明它期待获得的数据
那么页面中就会渲染出:Hello linxin单向数据流
当父组件的 name 发生改变,子组件也会自动地更新视图。但是在子组件中,我们不要去修改 prop。如果你必须要修改到这些数据,你可以使用以下方法:
方法一:把 prop 赋值给一个局部变量,然后需要修改的话就修改这个局部变量,而不影响 prop
export default {
data(){
newMessage: null
},
props: ['message'],
created(){
this.newMessage = this.message;
}
}
方法二:在计算属性中对 prop 进行处理 export default { props: ['message'], computed{ newMessage(){ return this.message + ' 哈哈哈'; } } }
自定义事件
prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。修改子组件的 prop 值,是不会传回给父组件去更新视图的。那么子组件要如何去与父组件通讯呢?
那就是自定义事件。通过在父组件 emit(eventName) 触发该自定义事件的时候,父组件执行相应的操作。
比如在父组件中控制一个弹框子组件的显示,在子组件中按下关闭之后,告诉父组件去隐藏它,然后父组件就执行操作隐藏弹框。
在子组件 dialog.vue 中:
这样就实现了父子组件之间的相互通讯。Vuex:实现组件与组件间通信, 创建,created 挂载:mounted 更新:update 销毁:destroy vue使用了标准html来写模版,借助极小的模版语法可以做一些简单的事,创建重复的基于视图数据的元素。 vue2.0几个常用知识点:路由懒加载, { path:'/development', name:'development', component:(resolve)=>{ require(['../views/development.vue'], resolve) } } 通过路由的的beforeEach钩子函数来判断是否需要登录 { path: '/system', name: '系统设置', meta: { login: true }, component: import('System/index') } router.beforeEach((to, from, next) => { if (to.meta.login) { //判断前往的界面是否需要登陆 if (store.state.user.user.name) { // 是否已经登陆 next() }else{ Vue.prototype.$alert('请先登录!') .then( () => { store.state.user.isLogin = true }) } }else{ if (to.meta.page) store.state.app.pageLoading = true next() }
}) 动画切换:通过检测设置在 Router上的animate属性 来判断它做什么样的切换动画。 Router.prototype.animate = 0 // 获取每个路由meta上面的slide 来判断它做什么动画 { path: '/system', name: '系统设置', meta: { slide: 1 }, component: import('System/index') } watch: { $route (to, from) {
0: 不做动画
1: 左切换
2: 右切换
3: 上切换
4: 下切换
let animate = this.$router.animate || to.meta.slide
if (!animate) {
this.animate = ''
}else{
this.animate = animate === 1 ? 'slide-left' :
animate === 2 ? 'slide-right' :
animate === 3 ? 'slide-top' :
animate === 4 ? 'slide-bottom' : ''
}
this.$router.animate = 0
}
}
项目目录:├─.babelrc // babel 配置文件
├─index.template.html // html 模板文件
├─server.js // 提供服务端渲染及 api 服务
├─src // 前端代码
| ├─app.js // 主要用于创建 vue 实例
| ├─App.vue // 根组件
| ├─entry-client.js // 客户端渲染入口文件
| ├─entry-server.js // 服务端渲染入口文件
| ├─stores // vuex 相关
| ├─routes // vue-router 相关
| ├─components // 组件
├─dist // 代码编译目标路径
├─build // webpack 配置文件
搭建vue开发环境:利用 webpack 可以非常快速的搭建一个简单的 vue 开发环境,可以直接乘电梯前往。
为了高效地进行开发,vue 开发环境应该有代码热加载和请求转发的功能。这些都可以使用 webpack-dev-server 来轻松实现,只需配置 webpack 的 devServer 项:
module.exports = merge(baseWebpackConfig, { devServer: { historyApiFallback: true, noInfo: true, overlay: true, proxy: config.proxy }, devtool: '#eval-source-map', plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', template: 'index.template.html', inject: true // 插入css和js }), new webpack.HotModuleReplacementPlugin(), new FriendlyErrors() ] })
启动时添加--hot参数即可。
在项目根目录下运行 npm run server 启动后端 api 服务,然后运行 npm run dev ,webpack 会自动在默认浏览器中打开 http://localhost:8080 地址,看到效果。
要实现服务端渲染,只需增加如下 webpack 配置:
module.exports = merge(baseWebpackConfig, {
entry: './src/entry-server.js',
// 告知 vue-loader 输送面向服务器代码(server-oriented code)。
target: 'node',
output: {
filename: 'server-bundle.js',
libraryTarget: 'commonjs2',
},
plugins: [
new VueSSRServerPlugin()
]
})
entry 的文件路径跟之前的不太一样,这里使用的是专门为服务端渲染准备的入口文件。 import { createApp } from './app' // 这里的 context 是服务端渲染模板时传入的 export default context => { // 因为有可能会是异步路由钩子函数或组件,所以我们将返回一个 Promise, // 以便服务器能够等待所有的内容在渲染前, // 就已经准备就绪。 return new Promise((resolve, reject) => { const { app, router, store } = createApp()
const { url } = context
const { fullPath } = router.resolve(url).route
if (fullPath !== url) {
return reject({ url: fullPath })
}
router.push(url)
// 等到 router 将可能的异步组件和钩子函数解析完
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
// 匹配不到的路由,执行 reject 函数,并返回 404
if (!matchedComponents.length) {
return reject({ code: 404 })
}
// 执行所有组件中的异步数据请求
Promise.all(matchedComponents.map(({ asyncData }) => asyncData && asyncData({
store,
route: router.currentRoute
}))).then(() => {
context.state = store.state
resolve(app)
}).catch(reject)
}, reject)
}) }
其中的 asyncData 可能会让人疑惑,稍后我们用一个例子来说明。现在,然我们来编译一下,运行 npm run build:server ,将会在 dist 目录下得到 vue-ssr-server-bundle.json 文件。可以看到,该文件包含了 webpack 打包生成的所有 chunk 并指定了入口。后面服务端会基于该文件来做渲染。
// 服务端渲染 server.get('*', (req, res) => { const context = { url: req.originalUrl } renderer.renderToString(context, (err, html) => { if (err) { if (err.code === 404) { res.status(404).end('Page not found') } else { res.status(500).end('Internal Server Error') } } else { res.end(html) } }) })
新增代码不多,首先使用上面生成的文件创建了一个 renderer 对象,然后调用其 renderToString 方法并传入包含请求路径的对象作为参数来进行渲染,最后将渲染好的数据即 html 返回。
运行 npm run server 启动服务端,打开 http://localhost:8081 就可以看到效果了:
关于 asyncData: 前面提到了 asyncData ,现在以该例子来梳理一下。首先,看看组件中的代码:
这是一个很简单的组件,包括一个列表,该列表的内容通过请求从后端获取,一个表单,用于提交新的记录到后端保存。其中 asyncData 是我们约定的函数名,表示渲染组件需要预先执行它获取初始数据,它返回一个 Promise,以便我们在后端渲染的时候可以知道什么时候该操作完成。这里,该函数触发了 fetchItems 以更新 store 中的状态。还记得我们的 entry-server.js 文件吗,里面正是调用了组件的 asyncData 方法来进行数据预取的。
在开发阶段,我们同样需要进行数据预取,为了复用 asyncData 代码,我们在组件的 beforeMount 中调用该方法,我们将这个处理逻辑通过 Vue.mixin 混入到所有的组件中:
Vue.mixin({
beforeMount() {
const { asyncData } = this.store,
route: this.$route
})
}
}
})
我们生成的 html 中并没有引入任何 js,用户无法进行任何交互,比如上面的列表页,用户无法提交新的内容。当然,如果这个页面是只给爬虫来“看”的话这样就足够了,但如果考虑到真实的用户,我们还需要在 html 中引入前端渲染的 js 文件。
前端渲染部分需要先增加一个 webpack 的配置文件用于生成所需的 js, css 等静态文件:
module.exports = merge(baseWebpackConfig, {
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: true
}
}),
// 重要信息:这将 webpack 运行时分离到一个引导 chunk 中,
// 以便可以在之后正确注入异步 chunk。
// 这也为你的 应用程序/vendor 代码提供了更好的缓存。
new webpack.optimize.CommonsChunkPlugin({
name: "manifest",
minChunks: Infinity
}),
// 此插件在输出目录中
// 生成
vue-ssr-client-manifest.json。
new VueSSRClientPlugin()
]
})
同时,前端渲染还需要有自己的入口文件 entry-client,该文件在讲 asyncData 的时候有所提及:
import Vue from 'vue'
import {
createApp
} from './app.js'
// 客户端特定引导逻辑……
const {
app,
router,
store
} = createApp()
if (window.INITIAL_STATE) {
store.replaceState(window.INITIAL_STATE)
}
Vue.mixin({
beforeMount() {
const { asyncData } = this.store,
route: this.
mount('#app')
})
在server.js中:
const clientManifest = require('./dist/vue-ssr-client-manifest.json')
const renderer = createBundleRenderer(bundle, { template: fs.readFileSync('./index.template.html', 'utf-8'), clientManifest }) 然后 npm run server 启动服务,再打开 http://localhost:8081,可以看到渲染后的 html 文件中已经引入了 js 资源了。