- 下载与资源
- 当前版本
- MVVM图示
- 安装Vue
- nrm的安装
- 导入和导出js
- Vue基础
- BootstrapVue
- 页面布局图示
- 导入子组件
- 切换组件router-link
- axios
- 父组件向子组件传值传方法
- 子组件主动获取父组件数据和方法
- 父组件主动获取子组件数据和方法
- $refs获取DOM对象和组件
- vue-router基本使用
- vue-router切换时的当前路径的高亮显示
- vue-router路由传参
- 子路由(路由嵌套)的设计
- 命名视图布局
- 命名视图的形式跳转路由
- 编程式路由
- 全局权限router.beforeEach
- vuex
- vue-cookies
- mavonEditor
- 语言组件vue-i18n
- 过滤器filter
- 计算和监听事件
- 实时更新数据this.$set
- 实时切换显示或隐藏元素
- 实现全局公共方法
- 页面加载数据之前增加loading动画
- 页脚固定在底部
- 下拉菜单
- 拖动排序
- 西瓜播放器
- video.js播放器
- vue的报错
- 动态检查用户名是否已存在
- 手机端配置
- 路由的历史模式和哈希模式
- 递归组件展示父子回复
- url生成二维码
主站 | Vue Cli | vue api | Vue详细手记 | BootstrapVue | mpvue(小程序) | 项目布署 | 网站图标svg |
node v12.13.0 / npm 6.12.0 / [email protected] / @vue/cli 4.1.1
"dependencies": {
"bootstrap": "^4.4.1",
"bootstrap-vue": "^2.1.0",
"core-js": "^3.4.3",
"dsteem": "^0.11.3",
"ipfs-http-client": "^40.1.0",
"mavon-editor": "^2.7.7",
"steem": "^0.7.10",
"vue": "^2.6.10",
"vue-cookies": "^1.6.1",
"vue-router": "^3.1.3",
"vuex": "^3.1.2"
},
1.使用cnpm, 注册为国内的镜像,使用cnpm代替npm
npm install -g cnpm --registry=https://registry.npm.taobao.org
2.cnpm install -g @vue/cli
vue --version
3.创建一个新项目
vue create hello-world
//babel router vuex 选择这三项就可以了
//sass可以不选填,它是css语法的拓展
//eslink 是检查语法的,可以不用
4. 运行
cnpm run serve
5. 打包
cnpm run build
nrm 是一个npm源管理器,允许你快速地在如下npm源间切换:
npm install nrm -g
nrm ls
nrm use taobao //切换不同的镜像源
npm install cnpm -g //安装cnpm工具
//text.js
export default {
name: 'tiantian',
age: 28
}
export let title = 'every'
//main.js
import tt from './text.js'
import {title} from './text.js'
console.log(tt) //tt.name tt.age
cnpm install bootstrap-vue bootstrap --save
//src/main.js
import BootstrapVue from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)
主要是在 App.vue 中布局。 主要分三步:引入,注册及使用。
<template>
<div id="app">
<Header></Header> //3.使用
<Banner></Banner>
</div>
</template>
<script>
import Banner from '@/components/Banner' // 1.引入
import Header from '@/components/Header'
export default {
name: 'App',
data(){
return {
}
},
methods:{
logout(){
this.$store.commit('clearToken')
}
},
components: {
Banner, //2.注册
Header
}
}
</script>
<template>
<div id="app">
<router-link to="/index">首页</router-link>
<router-link to="/course">课程</router-link>
<router-link to="/manage">管理</router-link>
<div v-if="$store.state.token">
<a>{{ $store.state.username }}</a>
<a @click="logout">注销</a>
</div>
<div v-else >
<router-link to="/register">注册</router-link>
<router-link to="/login">登录</router-link>
</div>
<router-view/>
</div>
</template>
cnpm install axios --save
//main.js
import axios from 'axios'
Vue.prototype.axios = axios
//其它js中使用:
this.axios({......})
//或者是哪里使用哪里就导入:
import axios from 'axios'
axios.get(){}
注:Promise尽量使用箭头函数,没有this的问题.
methods:{
get(){ //尽量使用箭头函数,没有this的问题
this.axios.get('http://vue.studyit.io/api/getlunbo').then(res => {
console.log(res.data)
}).catch(error => {
console.log(error)
})
}
}
this.axios.request({
method: 'post',
url: 'http://192.168.1.101:8000/login/',
data:{
username:this.username,
password:this.password
}
})
.then( (arg) => {
console.log(222,arg)
}
})
.catch((error) => {
console.log(333,error)
})
this.axios.request({
method:"get",
url:'http://192.168.1.101:8000/authors/'
}).then( (arg) => {
console.log(111,arg.data)
}).catch( (error) => {
console.log(333,error)
})
分两步走:
- 在父组件中动态绑定属性,:parentmsg='msg'
- 子组件中通过 props: 获取。 传方法也是差不多步骤.
//App.vue传值给Header.vue
//App.vue中的写法
<template>
<div id="app">
<Header :parentmsg="title" :func="parfun"></Header>
</div>
</template>
<script>
import Header from '@/components/Header'
export default {
name: 'App',
data(){
return {
title: '父组件中的数据'
}
},
methods:{
parfun(){
console.log('这是父方法')
}
},
components: {
Header
}
}
</script>
// Header.vue的写法
//在props中接受后可以直接使用
<template>
<div>
{{ parentmsg }}
<button @click="func">父方法</button>
</div>
</template>
<script>
export default {
name: "Header",
props: ['parentmsg', 'func']
}
</script>
直接在子组件中使用 this.$parent 即可获取父组件对象。 这种方法比较简单,但是不太直观,建议使用上一种方法。
主要是通过 $refs 获取子组件对象
- 绑定属性
- 获取子组件对象
//Test.vue
data(){
return {
str:'',
sonmsg: '这是子数据'
}
},
// App.vue
<Test ref="sonmsg"></Test> // 1. 绑定属性
mounted() {
console.log(566, this.$refs.sonmsg.sonmsg) // 2. 获取子组件对象
}
这也是调用子组件的方法
<input type="button" value="调用" @click="getElement">
<h3 ref="myh3">天天这样</h3>
getElement: function () {
console.log(this.$refs.myh3.innerText)
}
//如果是循环中使用$refs(v-for),那么它的元素会是一个数组!
<div v-for="">
<mavon-editor v-model="body" ref="mds" @imgAdd="upimg" style="height: 100%"/>
<div>
//mds: Array(3)
0: VueComponent {_uid: 91, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
1: VueComponent {_uid: 102, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
2: VueComponent {_uid: 113, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
length: 3
新版的vue中路由默认就是history模式(即url中没有# ,hash模式才有)
cnpm install vue-router --save
//使用,比如App.vue
<div id="app">
<router-link to="/login">login</router-link>
<router-link to="/register">register</router-link>
<router-view></router-view>
</div>
//vouter.js
import Register from '../components/Register'
import Login from '../components/Login'
{
path: '/register',
name: 'register',
component: Register
},
{
path: '/login',
name: 'login',
component: Login
},
//打开新页面-如果需要打开一个新窗口,vue2版本的 <router-link> 是支持 target="_blank" 属性的
<router-link target="_blank" :to="'/searcharticle/'+'@'+post.author+'/'+post.permlink">{{ post.created }}</router-link>
<a href="https://signup.steemit.com" target="_blank">注册</a>
//直接刷新当前页面
this.$router.go(0)
//app.vue
<style>
//用这个类
.router-link-exact-active{
color:red;
border-bottom: 1px solid red;
}
.router-link-active{
color:red;
}
</style>
// 一个案例:文章列表到文章详情页
//注意:+ 号之间不能有空格!!它是绑定变量的,有空格的话会被加入
<router-link :to="'/article/'+post.permlink">{{ post.title }}</router-link>
//router.js
path: '/article/:permlink'
//article.vue 取值方法
let permlink = this.$route.params.permlink
// this.$route 和 this.$router 的区别
this.$route是路由参数对象,params,query都属于它
this.$router是路由导航对象,可以实现路由的跳转
<div id="app">
<router-link to="/login">login</router-link>
<router-link to="/register">register</router-link>
<router-view></router-view>
</div>
<template id="tmp">
<div>
<router-link to="/register/weibo">微博注册</router-link>
<router-link to="/register/phone">手机注册</router-link>
<router-view></router-view>
</div>
</template>
var login = {
template: '<h1>login组件</h1>'
}
var weibo = {
template: '<h1>weibo组件</h1>'
}
var phone = {
template: '<h1>phone组件</h1>'
}
var register = {
template: '#tmp'
}
var router = new VueRouter({
routes: [
{path: '/', redirect: '/login'},
{path: '/login', component: login} ,
{path: '/register', component: register,
children: [
{path: 'weibo',component: weibo},
{path: 'phone',component: phone}
]
}
]
})
(name指定组件名),多个组件布置
<div id="app">
<router-view></router-view>
<router-view name="left"></router-view>
<router-view name="main"></router-view>
</div>
var header= {
template: '<h1>header组件</h1>'
}
var left = {
template: '<h1>left组件</h1>'
}
var main = {
template: '<h1>main组件</h1>'
}
var router = new VueRouter({
routes: [
{path: '/', components: {
default: header,
left: left,
main: main
}}
]
})
<div id="app">
<router-link :to="{name: 'login'}">login</router-link>
<router-link :to="{name: 'login',params:{id:10}}">login</router-link>
//传参的形式
<router-view></router-view>
</div>
<button @click='jumpto'> 点击跳转 </button>
<script>
methods: {
jumpto (){
this.$router.push('/cart')
//this.$router.push({path: '/cart'})
//this.$router.push({path: '/cart' + id})
}
}
</script>
//main.js
router.beforeEach(function (to, from, next) {
if(to.meta.requireAuth){
// 要去的url只有登陆成功后才能访问
if (store.state.username) {
next()
} else {
next({name: 'login'})
}
}else{
next()
}
})
//routers.js
routes: [
{
path: '/micro',
name: 'micro',
component: Micro,
meta:{
requireAuth:true
}
},
{
path: '/news',
name: 'news',
component: News,
meta:{
requireAuth:true
}
},
{
path: '/login',
name: 'login',
component: Login
}
],
vue配套的公共数据管理工具,它可以把一些共享的数据保存到vuex中,实现不同组件传值,并且数据持久化。
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。小项目可以直接用H5的 localStorage 、 sessionStorage
cnpm install vuex --save
import Vuex from 'vuex'
Vue.use(Vuex)
var store = new Vuex.Store({
state: {
count: 0 //this.$store.state.count调用数据
},
mutations: {
increment(state){
state.count ++
}, //this.$store.commit('increment')调用方法
getters: {
optCount: function (state) {
return state.count //只对外提供数据,$store.getters.optCount
}
}
}
})
//挂载到VM实例上
var app = new Vue({
el: '#app',
store
})
总结:
1. state中的数据,不能直接修改,如果想要修改,必须通过 mutations
2. 如果组件想要直接 从 state 上获取数据: 需要 this.$store.state.***
3. 如果 组件,想要修改数据,必须使用 mutations 提供的方法,需要通过 this.$store.commit('方法的名称', 唯一的一个参数(可以拼成对象))
that.$store.commit('saveUser', {username: that.username, password: privWif})
4. 如果 store 中 state 上的数据, 在对外提供的时候,需要做一层包装,那么 ,推荐使用 getters, 如果需要使用 getters ,则用 this.$store.getters.***
cnpm install vue-cookies --save
// main.js
import Vue from 'vue'
import VueCookies from 'vue-cookies'
Vue.use(VueCookies)
// 应用
Set a cookie
this.$cookies.set(keyName, value[, expireTimes[, path[, domain[, secure]]]]) //return this
Get a cookie
this.$cookies.get(keyName) // return value
Remove a cookie
this.$cookies.remove(keyName [, path [, domain]]) // return false or true , warning: next version return this; use isKey(keyname) return true/false,please
Exist a cookie name
this.$cookies.isKey(keyName) // return false or true
Get All cookie name
this.$cookies.keys() // return a array
//设置案例
this.$cookies.set("user_session","25j_7Sl6xDq2Kc3ym0fmrSSk2xV2XkUkX")
// number + d , ignore case
.set("user_session","25j_7Sl6xDq2Kc3ym0fmrSSk2xV2XkUkX","1d")
.set("user_session","25j_7Sl6xDq2Kc3ym0fmrSSk2xV2XkUkX","1D")
// Base of second
.set("user_session","25j_7Sl6xDq2Kc3ym0fmrSSk2xV2XkUkX",60 * 60 * 24)
// input a Date, + 1day
.set("user_session","25j_7Sl6xDq2Kc3ym0fmrSSk2xV2XkUkX", new Date(2017, 03, 12))
// input a date string, + 1day
.set("user_session","25j_7Sl6xDq2Kc3ym0fmrSSk2xV2XkUkX", "Sat, 13 Mar 2017 12:25:57 GMT")
//另一种写法
import Cookie from 'vue-cookies'
Cookie.set("username", userobj.username, "20min") //分钟
Cookie.set("username", userobj.username, "1d") //天
Cookie.get("username")
Cookie.remove('username')
markdown编辑器和解析器
cnpm install mavon-editor --save
// main.js
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
Vue.use(mavonEditor)
new Vue({
'el': '#main',
data() {
return { value: '' }
}
})
//使用
<div id="main">
<mavon-editor v-model="body" ref="md" @imgAdd="imgAdd" style="height: 100%"/>
</div>
//methods
imgAdd(pos, $file){
// 第一步.将图片上传到服务器sm.ms.
var formdata = new FormData();
formdata.append('smfile', $file);
this.axios({
url: 'https://sm.ms/api/v2/upload',
method: 'post',
data: formdata,
headers: { 'Content-Type': 'multipart/form-data' },
}).then((url) => {
// 第二步.将返回的url替换到文本原位置 -> 
console.log(899, url)
this.$refs.md.$img2Url(pos, url.data.data.url)
})
},
//解析成html文本
<mavon-editor
class="md"
:value="post.body" //绑定的变量
:subfield = "prop.subfield"
:defaultOpen = "prop.defaultOpen"
:toolbarsFlag = "prop.toolbarsFlag"
:editable="prop.editable"
:scrollStyle="prop.scrollStyle"
></mavon-editor>
computed: {
prop () {
let data = {
subfield: false,
defaultOpen: 'preview',
editable: false,
toolbarsFlag: false,
scrollStyle: true
}
return data
}
},
常见的文本格式化,只能用在插值表达式和v-bind表达式中。实质是对数据进行处理,执行了函数。
<li>{{ post.created | formatTime }}</li>
filters:{
formatTime(data){
return data.substring(0,10)
}
},
watch 监听事件的变化,一有变化,立刻执行!
可以监听数据的实时变化,设一个data, 一个temp,监听temp。将会有变化的数据赋值给temp,监听到变化,会立刻赋值给data。这样可以达到实时渲染数据的目的。
<template>
<div>
++{{ data.id }}--{{ data.body }}++
</div>
</template>
<script>
export default {
name: "Testwatch",
data() {
return {
data: {id:1, body:'hello'},
temp:{},
}
},
watch:{
temp(){
this.data = this.temp
}
}
}
</script>
computer对于任何复杂逻辑,你都应当使用计算属性。所有的计算属性都是以函数的形式写在Vue实例内的computed选项内,最终返回计算后的结果。
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
show: function () {
return show = true;
},
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
可以动态更新data中的数据显示,也就是操作data的方法
data() {
return {
post: {id:1, body:'hello'},
}
},
methods:{
addCollection() {
this.$set(this.post, 'id', 3) //更改id值
this.$set(this.post, "body", "world")
this.$set(this.post, "child", []) //增加一个child属性
},
<template>
<div v-for="(t, key) in data">
{{ t.name }}--{{ key}}
<div v-show="flag[key]">出来吧,阿里巴巴</div>
<button @click="show(key)">显示</button>
</div>
</template>
<script>
export default {
name: "Test",
data(){
return {
data:[{name:'tian', age:20},
{name:'hello', age:30},
{name:'today', age:50}
],
flag:[],
}
},
methods:{
show(key){
//因为是下标的形式,数据不会实时渲染!
//要使用this.$set的形式来修改它的值,这样就可以实时渲染,以实现切换的效果了。
this.$set(this.flag, key, !this.flag[key])
for(let i=0;i<this.data.length;i++){
//将其它的隐藏掉
if(key != i){
this.$set(this.flag, i, false)
}
}
},
mounted() {
for(let i=0; i<this.data.length;i++){
this.flag[i] = false
}
}
}
</script>
对于常用的重复使用的代码,可以把它写成公共方法,然后在全局使用即可 主要有两步: 1.utils -> 定义方法或变量,export 2.main.js中导入并挂载到全局。
//utils/getstr.js
const getstr = function(){
function randomString(length, chars) {
let result = ''
for (let i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)]
return result
}
return randomString(5, '0123456789abcdefghijklmnopqrstuvwxyz')
}
export {getstr}
//main.js
import {getstr} from "./utils/getstr"
Vue.prototype.getstr = getstr
全局即可使用:this.getstr
1. loading.vue组件
<template>
<div class="loading"></div>
</template>
<script>
export default {
name: "Loading"
}
</script>
<style scoped>
.loading {
margin: 0 auto;
background: url('../../static/images/loading.gif') center center no-repeat #fff;
width: 50vw;
height: 50vh;
z-index: 1000;
}
</style>
2. App.vue 全局的css
.fade-enter,
.fade-leave-active {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
3. 在组件中引用
<template>
<!--加载动画-->
<transition name="fade">
<loading v-if="isLoading"></loading>
</transition>
</template>
<script>
import Loading from './Loading'
export default {
name: "Feed",
data(){
return{
isLoading: true
}
},
methods:{
loadPageData: function() {
// axios 请求页面数据 .then 中将状态值修改this.isLoading = false
this.isLoading = false
}
},
components: {
Loading
},
mounted() {
this.loadPageData()
},
</script>
//App.vue
html,body{
height: 100%;
}
#app{
position:relative;
width:100%;
min-height:100%;
padding-bottom: 4rem;
box-sizing: border-box;
}
//footer.vue
.myfooter{
background-color: rgba(228,231,233,0.75);
color: rgba(55,53,58,0.75);
width: 100%;
height: 4rem;
padding-top: 1rem;
padding-left: 3rem;
padding-right: 3rem;
position:absolute;
bottom:0px;
}
<div v-if="$store.state.username">
<div id="drop">
<b-dropdown id="dropdown-grouped" :text="$store.state.username" class="m-2">
<b-dropdown-item-button @click="comments">
评论
</b-dropdown-item-button>
<b-dropdown-divider></b-dropdown-divider>
<b-dropdown-item-button @click="reply">
回复
</b-dropdown-item-button>
<b-dropdown-divider></b-dropdown-divider>
<b-dropdown-item-button @click="logout">
注销
</b-dropdown-item-button>
</b-dropdown>
</div>
</div>
Vue.Draggable拖拽功能的配置和使用方法 | github
cnpm install xgplayer --save
cnpm install xgplayer-mp4 --save
<div id="vs"></div>
import Player from 'xgplayer';
const player = new Player({
id: 'vs',
url: 'http://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo.mp4'
})
npm install --save-dev video.js
npm install video.js@next
Vue.config.productionTip = false
Vue.config.devtools = true
Vue.config.devtools = true
//devtools可以通过开发环境配置
Vue.config.devTools = process.env.NODE_ENV !== 'production'
start = "2020-01-06T01:59:45"
主要是使用@keyup的动态事件,键盘一输入,就执行检查函数,以得到结果。 动态绑定样式表,将得到的结果切换显示。主要用于注册等操作。
<b-input
id="inline-form-input-name"
:class="checkFlag ? 'isok': 'isfalse'"
placeholder="请输入用户名(3位以上英文 或 英文加数字)"
v-model="username"
@keyup="checkuser"
></b-input>
data() {
return {
username:'',
checkFlag: true,
}
},
checkuser(){
let that = this
const username = this.username
if(username.length < 3){
return this.checkFlag=false
}
async function main(){
const ac = await that.client.database.call('lookup_account_names', [[username]])
// return (ac[0] === null) ? true : false;
console.log(123, ac[0])
if(ac[0] !== null){
console.log("1111, 用户名已存在!")
that.checkFlag = false
}else{
console.log(234567, '开始注册')
that.checkFlag = true
}
}
main()
},
<style scoped>
.isok{
margin-top: 1.5rem;
width: 50%;
/*background-color: chartreuse;*/
}
.isfalse{
margin-top: 1.5rem;
width: 50%;
background-color: crimson;
}
</style>
它会自动判断是不是手机端,如果是,则使用以下样式!
@media only screen and (max-width:768px) {
#moochain{
width: 96%;
margin: 0 auto;
}
.classlist{
padding-left: 0.5rem;
width: 98%;
margin: 0 auto;
}
}
//router.js
const router = new VueRouter({
mode: 'hash',
// mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
历史模式(history)的路径比较好看,比如:https://steemjiang.com/hotarticle/6725b
但是,会碰到刷新就404的错误!这个可以在nginx的配置中设置:
location / {
root /home/dist-steemjiang;
index index.html index.htm;
if (!-e $request_filename) { #history模式的设置
rewrite ^/(.*) /index.html last;
break;
}
}
哈希模式(hash), 路径中有'#',比如:https://starnote.github.io/#/starnote/7s4b6
它无需任何额外的配置,所以,在github中可以直接使用!
将递归类的数据递归展示出来,比如回复和子回复
需要主组件和递归组件两个组件来完成
//主组件 Reply.vue
<template>
<div class="reply">
<div v-for="item in replies">
<Replylist :parentmsg="item"></Replylist>
</div>
</div>
</template>
<script>
import Replylist from './Replylist'
export default {
name: "Reply",
data(){
return {
replies:[],
}
},
components: {
Replylist
}
}
</script>
//递归组件 Replylist.vue
<template>
<div class="item">
@{{ parentmsg.author}} {{ parentmsg.body}}
<ul v-if="parentmsg.child" class="child">
<Replylist v-for="(item,index) in parentmsg.child" :parentmsg="item" :key="index"></Replylist>
</ul>
</div>
</template>
<script>
export default {
name: "Replylist",
props: ['parentmsg']
}
</script>