nrm
npm i nrm -g
nrm ls
nrm use npm
nrm use taobao
npm i webpack -g
npm i webpack --save-dev
<div id="app"> <p>{{info}}</p> <input type="button" value="开启" v-on:click="go"> <input type="button" value="停止" v-on:click="stop"> </div>
// 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: { info: '猥琐发育,别浪~!', intervalId: null }, methods: { go() { // 如果当前有定时器在运行,则直接return if (this.intervalId != null) { return; } // 开始定时器 this.intervalId = setInterval(() => { this.info = this.info.substring(1) + this.info.substring(0, 1); }, 500); }, stop() { clearInterval(this.intervalId); } } });
<div id="app"> <input type="text" v-model="n1"> <select v-model="opt"> <option value="0">+</option> <option value="1">-</option> <option value="2">*</option> <option value="3">÷</option> </select> <input type="text" v-model="n2"> <input type="button" value="=" v-on:click="getResult"> <input type="text" v-model="result"> </div>
// 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: { n1: 0, n2: 0, result: 0, opt: '0' }, methods: { getResult() { switch (this.opt) { case '0': this.result = parseInt(this.n1) + parseInt(this.n2); break; case '1': this.result = parseInt(this.n1) - parseInt(this.n2); break; case '2': this.result = parseInt(this.n1) * parseInt(this.n2); break; case '3': this.result = parseInt(this.n1) / parseInt(this.n2); break; } } } });
2.2.0+ 的版本里,当在组件中使用 v-for 时,key 现在是必须的。
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。
searchName
<hr> 输入筛选名称: <input type="text" v-model="searchName">
v-for
item in list
in
<tbody> <tr v-for="item in search(searchName)"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.ctime}}</td> <td> <a href="#" @click.prevent="del(item.id)">删除</a> </td> </tr> </tbody>
search
filter
search(name) { return this.list.filter(x => { return x.name.indexOf(name) != -1; }); }
Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两个地方:mustache 插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示;
私有过滤器
<td>{{item.ctime | dataFormat('yyyy-mm-dd')}}</td>
filters
filters: { // 私有局部过滤器,只能在 当前 VM 对象所控制的 View 区域进行使用 dataFormat(input, pattern = "") { // 在参数列表中 通过 pattern="" 来指定形参默认值,防止报错 var dt = new Date(input); // 获取年月日 var y = dt.getFullYear(); var m = (dt.getMonth() + 1).toString().padStart(2, '0'); var d = dt.getDate().toString().padStart(2, '0'); // 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日 // 否则,就返回 年-月-日 时:分:秒 if (pattern.toLowerCase() === 'yyyy-mm-dd') { return `${y}-${m}-${d}`; } else { // 获取时分秒 var hh = dt.getHours().toString().padStart(2, '0'); var mm = dt.getMinutes().toString().padStart(2, '0'); var ss = dt.getSeconds().toString().padStart(2, '0'); return `${y}-${m}-${d} ${hh}:${mm}:${ss}`; } } } //使用ES6中的字符串新方法 String.prototype.padStart(maxLength, fillString='') 或 //String.prototype.padEnd(maxLength, fillString='')来填充字符串;
全局过滤器
// 定义一个全局过滤器 Vue.filter('dataFormat', function (input, pattern = '') { var dt = new Date(input); // 获取年月日 var y = dt.getFullYear(); var m = (dt.getMonth() + 1).toString().padStart(2, '0'); var d = dt.getDate().toString().padStart(2, '0'); // 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日 // 否则,就返回 年-月-日 时:分:秒 if (pattern.toLowerCase() === 'yyyy-mm-dd') { return `${y}-${m}-${d}`; } else { // 获取时分秒 var hh = dt.getHours().toString().padStart(2, '0'); var mm = dt.getMinutes().toString().padStart(2, '0'); var ss = dt.getSeconds().toString().padStart(2, '0'); return `${y}-${m}-${d} ${hh}:${mm}:${ss}`; } }); 注意:当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用!
// 自定义全局指令 v-focus,为绑定的元素自动获取焦点: Vue.directive('focus', { inserted: function (el) { // inserted 表示被绑定元素插入父节点时调用 el.focus(); } }); // 自定义局部指令 v-color 和 v-font-weight,为绑定的元素设置指定的字体颜色 和 字体粗细: directives: { color: { // 为元素设置指定的字体颜色 bind(el, binding) { el.style.color = binding.value; } }, 'font-weight': function (el, binding2) { // 自定义指令的简写形式,等同于定义了 bind 和 update 两个钩子函数 el.style.fontWeight = binding2.value; } }
<input type="text" v-model="searchName" v-focus v-color="'red'" v-font-weight="900">
例一:
<div id="app"> <input type="button" value="动起来" @click="myAnimate"> <!-- 使用 transition 将需要过渡的元素包裹起来 --> <transition name="fade"> <div v-show="isshow">动画哦</div> </transition> </div>
// 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: { isshow: false }, methods: { myAnimate() { this.isshow = !this.isshow; } } });
/* 定义进入和离开时候的过渡状态 */ .fade-enter-active, .fade-leave-active { transition: all 0.2s ease; position: absolute; } /* 定义进入过渡的开始状态 和 离开过渡的结束状态 */ .fade-enter, .fade-leave-to { opacity: 0; transform: translateX(100px); }
使用第三方CSS动画库
<link rel="stylesheet" type="text/css" href="./lib/animate.css">
<transition enter-active-class="fadeInRight" leave-active-class="fadeOutRight" :duration="{ enter: 500, leave: 800 }"> <div class="animated" v-show="isshow">动画哦</div> </transition>
使用动画钩子函数
<div id="app"> <input type="button" value="切换动画" @click="isshow = !isshow"> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> <div v-if="isshow" class="show">OK</div> </transition> </div>
methods: { beforeEnter(el) { // 动画进入之前的回调 el.style.transform = 'translateX(500px)'; }, enter(el, done) { // 动画进入完成时候的回调 el.offsetWidth; el.style.transform = 'translateX(0px)'; done(); }, afterEnter(el) { // 动画进入完成之后的回调 this.isshow = !this.isshow; } }
.show{ transition: all 0.4s ease; }
v-for的列表过渡
<style> .list-enter, .list-leave-to { opacity: 0; transform: translateY(10px); } .list-enter-active, .list-leave-active { transition: all 0.3s ease; } </style>
<div id="app"> <input type="text" v-model="txt" @keyup.enter="add"> <transition-group tag="ul" name="list"> <li v-for="(item, i) in list" :key="i">{{item}}</li> </transition-group> </div>
// 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: { txt: '', list: [1, 2, 3, 4] }, methods: { add() { this.list.push(this.txt); this.txt = ''; } } });
列表的排序过渡
<transition-group> 组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move 特性,它会在元素的改变定位的过程中应用。
<transition-group>
v-move
v-leave-active
.v-move{ transition: all 0.8s ease; } .v-leave-active{ position: absolute; }
全局定义组件的三种方式
var login = Vue.extend({ template: '<h1>登录</h1>' }); Vue.component('login', login);
Vue.component('register', { template: '<h1>注册</h1>' });
<script id="tmpl" type="x-template"> <div><a href="#">登录</a> | <a href="#">注册</a></div> </script>
同时,需要使用 Vue.component 来定义组件:
Vue.component('account', { template: '#tmpl' });
组件中展示数据和响应事件
data
Vue.component('account', { template: '#tmpl', data() { return { msg: '大家好!' } }, methods:{ login(){ alert('点击了登录按钮'); } } });
this
【重点】为什么组件中的data属性必须定义为一个方法并返回一个对象
<script> // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: {}, methods: {}, components: { // 定义子组件 account: { // account 组件 template: '<div><h1>这是Account组件{{name}}</h1><login></login></div>', // 在这里使用定义的子组件 components: { // 定义子组件的子组件 login: { // login 组件 template: "<h3>这是登录组件</h3>" } } } } }); </script>
<div id="app"> <account></account> </div>
使用flag标识符结合v-if和v-else切换组件
flag
v-if
v-else
<div id="app"> <input type="button" value="toggle" @click="flag=!flag"> <my-com1 v-if="flag"></my-com1> <my-com2 v-else="flag"></my-com2> </div>
<script> Vue.component('myCom1', { template: '<h3>奔波霸</h3>' }) Vue.component('myCom2', { template: '<h3>霸波奔</h3>' }) // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: { flag: true }, methods: {} }); </script>
使用:is属性来切换不同的子组件,并添加切换动画
:is
// 登录组件 const login = Vue.extend({ template: `<div> <h3>登录组件</h3> </div>` }); Vue.component('login', login); // 注册组件 const register = Vue.extend({ template: `<div> <h3>注册组件</h3> </div>` }); Vue.component('register', register); // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: { comName: 'login' }, methods: {} });
component
<div id="app"> <a href="#" @click.prevent="comName='login'">登录</a> <a href="#" @click.prevent="comName='register'">注册</a> <hr> <transition mode="out-in"> <component :is="comName"></component> </transition> </div>
<style> .v-enter, .v-leave-to { opacity: 0; transform: translateX(30px); } .v-enter-active, .v-leave-active { position: absolute; transition: all 0.3s ease; } h3{ margin: 0; } </style>
props
<script> // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: { msg: '这是父组件中的消息' }, components: { son: { template: '<h1>这是子组件 --- {{finfo}}</h1>', props: ['finfo'] } } }); </script>
v-bind
<div id="app"> <son :finfo="msg"></son> </div>
getMsg
methods
func
<son @func="getMsg"></son>
this.$emit('方法名', 要传递的数据)
<div id="app"> <!-- 引用父组件 --> <son @func="getMsg"></son> <!-- 组件模板定义 --> <script type="x-template" id="son"> <div> <input type="button" value="向父组件传值" @click="sendMsg" /> </div> </script> </div> <script> // 子组件的定义方式 Vue.component('son', { template: '#son', // 组件模板Id methods: { sendMsg() { // 按钮的点击事件 this.$emit('func', 'OK'); // 调用父组件传递过来的方法,同时把数据传递出去 } } }); // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: {}, methods: { getMsg(val){ // 子组件中,通过 this.$emit() 实际调用的方法,在此进行定义 alert(val); } } }); </script>
this.$refs
<div id="app"> <div> <input type="button" value="获取元素内容" @click="getElement" /> <!-- 使用 ref 获取元素 --> <h1 ref="myh1">这是一个大大的H1</h1> <hr> <!-- 使用 ref 获取子组件 --> <my-com ref="mycom"></my-com> </div> </div> <script> Vue.component('my-com', { template: '<h5>这是一个子组件</h5>', data() { return { name: '子组件' } } }); // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: {}, methods: { getElement() { // 通过 this.$refs 来获取元素 console.log(this.$refs.myh1.innerText); // 通过 this.$refs 来获取组件 console.log(this.$refs.mycom.name); } } }); </script>
<!-- 1. 导入 vue-router 组件类库 --> <script src="./lib/vue-router-2.7.0.js"></script>
<!-- 2. 使用 router-link 组件来导航 --> <router-link to="/login">登录</router-link> <router-link to="/register">注册</router-link>
<!-- 3. 使用 router-view 组件来显示匹配到的组件 --> <router-view></router-view>
Vue.extend
// 4.1 使用 Vue.extend 来创建登录组件 var login = Vue.extend({ template: '<h1>登录组件</h1>' }); // 4.2 使用 Vue.extend 来创建注册组件 var register = Vue.extend({ template: '<h1>注册组件</h1>' });
// 5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则 var router = new VueRouter({ routes: [ { path: '/login', component: login }, { path: '/register', component: register } ] });
// 6. 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', router: router // 使用 router 属性来使用路由规则 });
在路由规则下定义参数
{ path: '/register/:id', component: register }
this.$route.params
var register = Vue.extend({ template: '<h1>注册组件 --- {{this.$route.params.id}}</h1>' });
children
<div id="app"> <router-link to="/account">Account</router-link> <router-view></router-view> </div> <script> // 父路由中的组件 const account = Vue.extend({ template: `<div> 这是account组件 <router-link to="/account/login">login</router-link> | <router-link to="/account/register">register</router-link> <router-view></router-view> </div>` }); // 子路由中的 login 组件 const login = Vue.extend({ template: '<div>登录组件</div>' }); // 子路由中的 register 组件 const register = Vue.extend({ template: '<div>注册组件</div>' }); // 路由实例 var router = new VueRouter({ routes: [ { path: '/', redirect: '/account/login' }, // 使用 redirect 实现路由重定向 { path: '/account', component: account, children: [ // 通过 children 数组属性,来实现路由的嵌套 { path: 'login', component: login }, // 注意,子路由的开头位置,不要加 / 路径符 { path: 'register', component: register } ] } ] }); // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: {}, methods: {}, components: { account }, router: router }); </script>
<div id="app"> <router-view></router-view> <div class="content"> <router-view name="a"></router-view> <router-view name="b"></router-view> </div> </div>
<script> var header = Vue.component('header', { template: '<div class="header">header</div>' }); var sidebar = Vue.component('sidebar', { template: '<div class="sidebar">sidebar</div>' }); var mainBox = Vue.component('mainBox', { template: '<div class="mainBox">mainBox</div>' }); // 创建路由对象 var router = new VueRouter({ routes: [ { path: '/', components: { default: header, a: sidebar, b: mainBox } } ] }); // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: {}, methods: {}, router }); </script>
<style> .header { border: 1px solid red; } .content{ display: flex; } .sidebar { flex: 2; border: 1px solid green; height: 500px; } .mainBox{ flex: 8; border: 1px solid blue; height: 500px; } </style>
watch
考虑一个问题:想要实现 名 和 姓 两个文本框的内容改变,则全名的文本框中的值也跟着改变;(用以前的知识如何实现???)
名
姓
<div id="app"> <input type="text" v-model="firstName"> + <input type="text" v-model="lastName"> = <span>{{fullName}}</span> </div> <script> // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: { firstName: 'jack', lastName: 'chen', fullName: 'jack - chen' }, methods: {}, watch: { 'firstName': function (newVal, oldVal) { // 第一个参数是新数据,第二个参数是旧数据 this.fullName = newVal + ' - ' + this.lastName; }, 'lastName': function (newVal, oldVal) { this.fullName = this.firstName + ' - ' + newVal; } } }); </script>
<div id="app"> <router-link to="/login">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view> </div> <script> var login = Vue.extend({ template: '<h1>登录组件</h1>' }); var register = Vue.extend({ template: '<h1>注册组件</h1>' }); var router = new VueRouter({ routes: [ { path: "/login", component: login }, { path: "/register", component: register } ] }); // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: {}, methods: {}, router: router, watch: { '$route': function (newVal, oldVal) { if (newVal.path === '/login') { console.log('这是登录组件'); } } } }); </script>
computed
getter
<div id="app"> <input type="text" v-model="firstName"> + <input type="text" v-model="lastName"> = <span>{{fullName}}</span> </div> <script> // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: { firstName: 'jack', lastName: 'chen' }, methods: {}, computed: { // 计算属性; 特点:当计算属性中所以来的任何一个 data 属性改变之后,都会重新触发 本计算属性 的重新计算,从而更新 fullName 的值 fullName() { return this.firstName + ' - ' + this.lastName; } } }); </script>
setter
<div id="app"> <input type="text" v-model="firstName"> <input type="text" v-model="lastName"> <!-- 点击按钮重新为 计算属性 fullName 赋值 --> <input type="button" value="修改fullName" @click="changeName"> <span>{{fullName}}</span> </div> <script> // 创建 Vue 实例,得到 viewmodel var vm = new Vue({ el: '#app', data: { firstName: 'jack', lastName: 'chen' }, methods: { changeName() { this.fullName = 'TOM - chen2'; } }, computed: { fullName: { get: function () { return this.firstName + ' - ' + this.lastName; }, set: function (newVal) { var parts = newVal.split(' - '); this.firstName = parts[0]; this.lastName = parts[1]; } } } }); </script>
在网页中会引用哪些常见的静态资源?
JS
CSS
Images
字体文件(Fonts)
模板文件
网页中引入的静态资源多了以后有什么问题??
如何解决上述两个问题
初步使用webpack打包构建列表隔行变色案例
npm init
cnpm i jquery --save
main.js
// 导入jquery类库 import $ from 'jquery' // 设置偶数行背景色,索引从0开始,0是偶数 $('#list li:even').css('backgroundColor','lightblue'); // 设置奇数行背景色 $('#list li:odd').css('backgroundColor','pink');
import
webpack 入口文件路径 输出文件路径
webpack src/js/main.js dist/bundle.js
使用webpack的配置文件简化打包时候的命令
webpack.config.js
// 导入处理路径的模块 var path = require('path'); // 导出一个配置对象,将来webpack在启动的时候,会默认来查找webpack.config.js,并读取这个文件中导出的配置对象,来进行打包处理 module.exports = { entry: path.resolve(__dirname, 'src/js/main.js'), // 项目入口文件 output: { // 配置输出选项 path: path.resolve(__dirname, 'dist'), // 配置输出的路径 filename: 'bundle.js' // 配置输出的文件名 } }
实现webpack的实时打包构建
webpack-dev-server
cnpm i webpack-dev-server --save-dev
package.json
scripts
"dev": "webpack-dev-server"
bundle.js
http://localhost:8080/
<script src="../bundle.js"></script>
--contentBase src
"dev": "webpack-dev-server --contentBase src"
同时修改index页面中script的src属性为<script src="bundle.js"></script>
<script src="bundle.js"></script>
使用html-webpack-plugin插件配置启动页面
html-webpack-plugin
由于使用--contentBase指令的过程比较繁琐,需要指定启动的目录,同时还需要修改index.html中script标签的src属性,所以推荐大家使用html-webpack-plugin插件配置启动页面.
--contentBase
cnpm i html-webpack-plugin --save-dev
// 导入处理路径的模块 var path = require('path'); // 导入自动生成HTMl文件的插件 var htmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: path.resolve(__dirname, 'src/js/main.js'), // 项目入口文件 output: { // 配置输出选项 path: path.resolve(__dirname, 'dist'), // 配置输出的路径 filename: 'bundle.js' // 配置输出的文件名 }, plugins:[ // 添加plugins节点配置插件 new htmlWebpackPlugin({ template:path.resolve(__dirname, 'src/index.html'),//模板路径 filename:'index.html'//自动生成的HTML文件的名称 }) ] }
script
实现自动打开浏览器、热更新和配置浏览器的默认端口号
注意:热更新在JS中表现的不明显,可以从一会儿要讲到的CSS身上进行介绍说明!
方式一:
--open
--port 4321
--hot
"dev": "webpack-dev-server --hot --port 4321 --open"
方式二:
devServer
devServer:{ hot:true, open:true, port:4321 }
webpack
var webpack = require('webpack');
plugins
new webpack.HotModuleReplacementPlugin()
使用webpack打包css文件
cnpm i less-loader less -D
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
使用webpack打包sass文件
cnpm i sass-loader node-sass --save-dev
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }
使用webpack处理css中的路径
cnpm i url-loader file-loader --save-dev
{ test: /\.(png|jpg|gif)$/, use: 'url-loader' }
limit
{ test: /\.(png|jpg|gif)$/, use: 'url-loader?limit=43960' },
使用babel处理高级JS语法
cnpm i babel-core babel-loader babel-plugin-transform-runtime --save-dev
cnpm i babel-preset-env babel-preset-stage-0 --save-dev
node_modules
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
.babelrc
{ "presets":["env", "stage-0"], "plugins":["transform-runtime"] }
在webpack中配置.vue组件页面的解析
cnpm i vue -S
cnpm i vue-loader vue-template-compiler -D
cnpm i style-loader css-loader -D
module
module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, { test: /\.vue$/, use: 'vue-loader' } ] }
App.js
<template> <!-- 注意:在 .vue 的组件中,template 中必须有且只有唯一的根元素进行包裹,一般都用 div 当作唯一的根元素 --> <div> <h1>这是APP组件 - {{msg}}</h1> <h3>我是h3</h3> </div> </template> <script> // 注意:在 .vue 的组件中,通过 script 标签来定义组件的行为,需要使用 ES6 中提供的 export default 方式,导出一个vue实例对象 export default { data() { return { msg: 'OK' } } } </script> <style scoped> h1 { color: red; } </style>
// 导入 Vue 组件 import Vue from 'vue' // 导入 App组件 import App from './components/App.vue' // 创建一个 Vue 实例,使用 render 函数,渲染指定的组件 var vm = new Vue({ el: '#app', render: c => c(App) });
在使用webpack构建的Vue项目中使用模板对象?
resolve
resolve: { alias: {//修改Vue被导入时候的包的路径,默认只是导入运行时vue包 'vue$': 'vue/dist/vue.esm.js' } }
import VueRouter from 'vue-router'
Vue.use(VueRouter);
import login from './components/account/login.vue' import register from './components/account/register.vue'
var router = new VueRouter({ routes: [ { path: '/', redirect: '/login' }, { path: '/login', component: login }, { path: '/register', component: register } ] });
var vm = new Vue({ el: '#app', // render: c => { return c(App) } render(c) { return c(App); }, router // 将路由对象,挂载到 Vue 实例上 });
router-link
router-view
<router-link to="/login">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view>
在组件中的要加上作用域,不然作用于全局
<style scoped> div { color: red; } </style>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。