首页

Vue 数据持久化

前端达人

方法一:使用 localStorage 存储数据

window.localStorage.setItem(key,value)

 

方法二:使用 vuex-persistedstate插件

vuex 存在一个痛点,就是刷新以后vuex里面存储的state就会被浏览器释放掉(state都是存储在内存中的)。

办法:

通过vuex-persistedstate插件,实现将数据存储到本地。

1.实现

import createPersistedState from 'vuex-persistedstate'
export default new Vuex.Store({
    state:{},
    getters:{},
    actions:{},
    mutations:{},
    modules:{},
    plugins: [createPersistedState()]  //加上这个就可以了 //里面设置需要缓存的内容
})

API:  https://www.npmjs.com/package/vuex-persistedstate

方法三: 使用vue-cookie插件

cookie 可以设置过期时间

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex)
var VueCookie = require('vue-cookie');

export default new Vuex.Store({
  state: {
    token: VueCookie.get('token')
  },
  mutations: {
    saveToken(state, token) {
      state.token = token;
      // 设置存储
      VueCookie.set('token', token, { expires: '30s' });
    }
  },
  actions: {

  }
})

Vue 中 axios 拦截器的封装

seo达人

在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中。他有很多优秀的特性,例如拦截请求和响应、取消请求、转换json、客户端防御cSRF等。

一 . 安装



npm install axios;

1

二 . 引入

在项目的src目录中,新建一个request文件夹,然后在里面新建一个http.js和一个api.js文件。http.js文件用来封装我们的axios,api.js用来统一管理我们的接口。

三 . 开始封装



在http.js中引入axios . vue及其他

import Axios from 'axios'; // 引入axios

import { Message, Loading, Notification } from 'element-ui'

import vue from 'vue';

1

2

3

http.js文件全部代码如下:



import Axios from 'axios';

import store from '../store';

import { Message, Loading, Notification } from 'element-ui'

import vue from 'vue';

// 环境的切换

if (process.env.NODE_ENV == 'development') {

  Axios.defaults.baseURL = "http://10.230.39.58:33390/devops";

}

else if (process.env.NODE_ENV == 'production') {

  Axios.defaults.baseURL = "http://10.230.39.58:33390/devops";

}

// request请求拦截器

Axios.defaults.withCredentials = true

vue.prototype.$axios = Axios

//请求超时时间

// Axios.defaults.timeout = 100000;

Axios.defaults.headers.get['Content-Type'] = "application/json"

Axios.interceptors.request.use(config => {

  const Basic = sessionStorage.getItem("basicParam")

  if (Basic) {

    config.headers.Authorization = Basic ${Basic};

  } else {

    console.log("无校验值");

  }

  return config;

}, error => {

  Promise.reject(error);

})

// respone返回拦截器

Axios.interceptors.response.use(

  response => {

    if (response.data.code !== 200) {

      Notification.error({

        title: '错误',

        message: response.data.message

      });

    }

    return response.data;

  }, error => {

    // Notification.error({

    //   title: '错误',

    //   message: '系统异常'

    // });

    console.log('err' + error);// for debug

    return Promise.reject(error);

  }

)



export default Axios;



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

api.js文件全部代码如下:



import axios from 'axios';

/

  封装get方法

 
@param url

  @param data

 
@returns {Promise}

 */



export function fetch(url, params = {}) {

  return new Promise((resolve, reject) => {

    axios.get(url, {

      params: params

    })

      .then(response => {

        resolve(response.data);

      })

      .catch(err => {

        reject(err)

      })

  })

}





/*

 
封装post请求

  @param url

 
@param data

  @returns {Promise}

 
/



export function _post(url, data = {}) {

  return new Promise((resolve, reject) => {

    axios.post(url, data)

      .then(response => {

        console.log(response,

          "response");



        resolve(response);

      }, err => {

        reject(err)

      })

  })

}



/

  • 封装patch请求
  • @param url
  • @param data
  • @returns {Promise}

    */



    export function patch(url, data = {}) {

      return new Promise((resolve, reject) => {

        axios.patch(url, data)

          .then(response => {

            resolve(response.data);

          }, err => {

            reject(err)

          })

      })

    }



    /**
  • 封装put请求
  • @param url
  • @param data
  • @returns {Promise}

    */



    export function put(url, data = {}) {

      return new Promise((resolve, reject) => {

        axios.put(url, data)

          .then(response => {

            resolve(response.data);

          }, err => {

            reject(err)

          })

      })

    }



    在main.js中引入api.js



    import { _post, fetch, patch, put } from './utils/api'

    //定义全局变量

    Vue.prototype.$post = post;

    Vue.prototype.$fetch = fetch;

    Vue.prototype.$patch = patch;

    Vue.prototype.$put = put;

    1

    2

    3

    4

    5

    6

    最后在组件里直接使用



     this.$post('/api/v2/movie/top250')

          .then((response) => {

            console.log(response)

          })

          



    其他方法用法相同




使用 vue 1.0.3 $set 函数遇到的坑

seo达人

vue 1.0.3  中 $set 函数是动态改变或添加一个 data 中的属性值时 属性 key 不可以使用纯数字。



例如:



var app = new Vue({

     el:"#app",

     data:{

         test:{

             k1:'v1',

             k2:'v2'

         }

     },

     methods:{

         changeTestValue:function{

             // 动态改变 test 中某一属性的值

             var key = 'test.k1';  // 改变 test 属性中的 k1 的值

             this.$set(key,'changev1');  // 此处执行没有问题

            // 改变 整个 test 的值可以使用

            this.$set('test',{k1:'change-demo-v1',k2:'change-demo-v2'});   // 此处执行没有问题

            // 动态给 test 增加一个属性  k3

            this.$set('test.k3','test-add-value3');   // 此处执行没有问题

 

 

            // 此处有坑 当你的 属性为全数字的时候,则 函数无效,不报错,但是也添加不上值。

            // 例如

            this.$set('test.123','test-add-123');  // 此处执行不报错,但是也没有效果。

 

 

            // 所以在使用老版本vue的时候尽量避免 属性 key 未纯数字,或其他特殊字符。

         }

     }

});



除了这个坑以外还有另外一个坑,不过没有具体试验,

watch 监听某一值得变化,好像有点问题, 实际结果是只要 data 中的任意一个值发生变化都会被捕捉到。







最后还是使用 vue 2.x  以上版本吧,bug 少很多。







另外 $set 函数在2.x 中使用方式有所变化。







this.$set(target,key,obj);



target 对象类型,是需要赋值或修改的对象,



key  是字符串类型, 是 target 对象的属性



obj  可以是字符串,可以是对象类型,是 你要修改的或增加的值


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

Vue 3.0 前瞻,体验 Vue Function API

seo达人

概述

Vue 2.x 及以前的高阶组件的组织形式或多或少都会面临一些问题,特别是在需要处理重复逻辑的项目中,一旦开发者组织项目结构组织得不好,组件代码极有可能被人诟病为“胶水代码”。而在 Vue 2.x 及之前的版本,解决此类问题的办法大致是下面的方案:



mixin

函数式组件

slots

笔者维护的项目也需要处理大量复用逻辑,在这之前,笔者一直尝试使用mixin的方式来实现组件的复用。有些问题也一直会对开发者和维护者造成困惑,如一个组件同时mixin多个组件,很难分清对应的属性或方法写在哪个mixin里。其次,mixin的命名空间冲突也可能造成问题。难以保证不同的mixin不用到同一个属性名。为此,官方团队提出函数式写法的意见征求稿,也就是RFC:Function-based component API。使用函数式的写法,可以做到更灵活地复用组件,开发者在组织高阶组件时,不必在组件组织上考虑复用,可以更好地把精力集中在功能本身的开发上。



注:本文只是笔者使用vue-function-api提前体验 Vue Function API ,而这个 API 只是 Vue 3.0 的 RFC,而并非与最终 Vue 3.x API 一致。发布后可能有不一致的地方。



在 Vue 2.x 中使用

要想提前在Vue 2.x中体验 Vue Function API ,需要引入vue-function-api,基本引入方式如下:



import Vue from 'vue';

import { plugin as VueFunctionApiPlugin } from 'vue-function-api';

 

Vue.use(VueFunctionApiPlugin);

基本组件示例

先来看一个基本的例子:



<template>

    <div>

        <span>count is {{ count }}</span>

        <span>plusOne is {{ plusOne }}</span>

        <button @click="increment">count++</button>

    </div>

</template>

 

<script>

import Vue from 'vue';

import { value, computed, watch, onMounted } from 'vue-function-api';

 

export default {

    setup(props, context) {

        // reactive state

        const count = value(0);

        // computed state

        const plusOne = computed(() => count.value + 1);

        // method

        const increment = () => {

            count.value++;

        };

        // watch

        watch(

            () => count.value 2,

            val => {

                console.log(`count
2 is ${val});<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br /> &nbsp; &nbsp; &nbsp; &nbsp; );<br /> &nbsp; &nbsp; &nbsp; &nbsp; // lifecycle<br /> &nbsp; &nbsp; &nbsp; &nbsp; onMounted(() =&gt; {<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(mounted);<br /> &nbsp; &nbsp; &nbsp; &nbsp; });<br /> &nbsp; &nbsp; &nbsp; &nbsp; // expose bindings on render context<br /> &nbsp; &nbsp; &nbsp; &nbsp; return {<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count,<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; plusOne,<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; increment,<br /> &nbsp; &nbsp; &nbsp; &nbsp; };<br /> &nbsp; &nbsp; },<br /> };<br /> &lt;/script&gt;<br /> 详解<br /> setup<br /> setup函数是Vue Function API 构建的函数式写法的主逻辑,当组件被创建时,就会被调用,函数接受两个参数,分别是父级组件传入的props和当前组件的上下文context。看下面这个例子,可以知道在context中可以获取到下列属性值<br /> <br /> const MyComponent = {<br /> &nbsp; &nbsp; props: {<br /> &nbsp; &nbsp; &nbsp; &nbsp; name: String<br /> &nbsp; &nbsp; },<br /> &nbsp; &nbsp; setup(props, context) {<br /> &nbsp; &nbsp; &nbsp; &nbsp; console.log(props.name);<br /> &nbsp; &nbsp; &nbsp; &nbsp; // context.attrs<br /> &nbsp; &nbsp; &nbsp; &nbsp; // context.slots<br /> &nbsp; &nbsp; &nbsp; &nbsp; // context.refs<br /> &nbsp; &nbsp; &nbsp; &nbsp; // context.emit<br /> &nbsp; &nbsp; &nbsp; &nbsp; // context.parent<br /> &nbsp; &nbsp; &nbsp; &nbsp; // context.root<br /> &nbsp; &nbsp; }<br /> }<br /> value &amp; state<br /> value函数创建一个包装对象,它包含一个响应式属性value:<br /> <br /> <br /> <br /> 那么为何要使用value呢,因为在JavaScript中,基本类型并没有引用,为了保证属性是响应式的,只能借助包装对象来实现,这样做的好处是组件状态会以引用的方式保存下来,从而可以被在setup中调用的不同的模块的函数以参数的形式传递,既能复用逻辑,又能方便地实现响应式。<br /> <br /> 直接获取包装对象的值必须使用.value,但是,如果包装对象作为另一个响应式对象的属性,Vue内部会通过proxy来自动展开包装对象。同时,在模板渲染的上下文中,也会被自动展开。<br /> <br /> import { state, value } from 'vue-function-api';<br /> const MyComponent = {<br /> &nbsp; &nbsp; setup() {<br /> &nbsp; &nbsp; &nbsp; &nbsp; const count = value(0);<br /> &nbsp; &nbsp; &nbsp; &nbsp; const obj = state({<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count,<br /> &nbsp; &nbsp; &nbsp; &nbsp; });<br /> &nbsp; &nbsp; &nbsp; &nbsp; console.log(obj.count) // 作为另一个响应式对象的属性,会被自动展开<br /> &nbsp;<br /> &nbsp; &nbsp; &nbsp; &nbsp; obj.count++ // 作为另一个响应式对象的属性,会被自动展开<br /> &nbsp; &nbsp; &nbsp; &nbsp; count.value++ // 直接获取响应式对象,必须使用.value<br /> &nbsp;<br /> &nbsp; &nbsp; &nbsp; &nbsp; return {<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count,<br /> &nbsp; &nbsp; &nbsp; &nbsp; };<br /> &nbsp; &nbsp; },<br /> &nbsp; &nbsp; template:<button @click="count++">{{ count }}</button>,<br /> };<br /> 如果某一个状态不需要在不同函数中被响应式修改,可以通过state创建响应式对象,这个state创建的响应式对象并不是包装对象,不需要使用.value来取值。<br /> <br /> watch &amp; computed<br /> watch和computed的基本概念与 Vue 2.x 的watch和computed一致,watch可以用于追踪状态变化来执行一些后续操作,computed用于计算属性,用于依赖属性发生变化进行重新计算。<br /> <br /> computed返回一个只读的包装对象,和普通包装对象一样可以被setup函数返回,这样就可以在模板上下文中使用computed属性。可以接受两个参数,第一个参数返回当前的计算属性值,当传递第二个参数时,computed是可写的。<br /> <br /> import { value, computed } from 'vue-function-api';<br /> &nbsp;<br /> const count = value(0);<br /> const countPlusOne = computed(() =&gt; count.value + 1);<br /> &nbsp;<br /> console.log(countPlusOne.value); // 1<br /> &nbsp;<br /> count.value++;<br /> console.log(countPlusOne.value); // 2<br /> &nbsp;<br /> // 可写的计算属性值<br /> const writableComputed = computed(<br /> &nbsp; &nbsp; // read<br /> &nbsp; &nbsp; () =&gt; count.value + 1,<br /> &nbsp; &nbsp; // write<br /> &nbsp; &nbsp; val =&gt; {<br /> &nbsp; &nbsp; &nbsp; &nbsp; count.value = val - 1;<br /> &nbsp; &nbsp; },<br /> );<br /> watch第一个参数和computed类似,返回被监听的包装对象属性值,不过另外需要传递两个参数:第二个参数是回调函数,当数据源发生变化时触发回调函数,第三个参数是options。其默认行为与 Vue 2.x 有所不同:<br /> <br /> lazy:是否会在组件创建时就调用一次回调函数,与 Vue 2.x 相反,lazy默认是false,默认会在组件创建时调用一次。<br /> deep:与 Vue 2.x 的 deep 一致<br /> flush:有三个可选值,分别为 'post'(在渲染后,即nextTick后才调用回调函数),'pre'(在渲染前,即nextTick前调用回调函数),'sync'(同步触发)。默认值为'post'。<br /> // double 是一个计算包装对象<br /> const double = computed(() =&gt; count.value * 2);<br /> &nbsp;<br /> watch(double, value =&gt; {<br /> &nbsp; &nbsp; console.log('double the count is: ', value);<br /> }); // -&gt; double the count is: 0<br /> &nbsp;<br /> count.value++; // -&gt; double the count is: 2<br /> 当watch多个被包装对象属性时,参数均可以通过数组的方式进行传递,同时,与 Vue 2.x 的vm.$watch一样,watch返回取消监听的函数:<br /> <br /> const stop = watch(<br /> &nbsp; &nbsp; [valueA, () =&gt; valueB.value],<br /> &nbsp; &nbsp; ([a, b], [prevA, prevB]) =&gt; {<br /> &nbsp; &nbsp; &nbsp; &nbsp; console.log(a is: ${a});<br /> &nbsp; &nbsp; &nbsp; &nbsp; console.log(b is: ${b});<br /> &nbsp; &nbsp; }<br /> );<br /> &nbsp;<br /> stop();<br /> 注意:在RFC:Function-based component API初稿中,有提到effect-cleanup,是用于清理一些特殊情况的副作用的,目前已经在提案中被取消了。<br /> <br /> 生命周期<br /> 所有现有的生命周期都有对应的钩子函数,通过onXXX的形式创建,但有一点不同的是,destoryed钩子函数需要使用unmounted代替:<br /> <br /> import { onMounted, onUpdated, onUnmounted } from 'vue-function-api';<br /> &nbsp;<br /> const MyComponent = {<br /> &nbsp; &nbsp; setup() {<br /> &nbsp; &nbsp; &nbsp; &nbsp; onMounted(() =&gt; {<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('mounted!');<br /> &nbsp; &nbsp; &nbsp; &nbsp; });<br /> &nbsp; &nbsp; &nbsp; &nbsp; onUpdated(() =&gt; {<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('updated!');<br /> &nbsp; &nbsp; &nbsp; &nbsp; });<br /> &nbsp; &nbsp; &nbsp; &nbsp; // destroyed 调整为 unmounted<br /> &nbsp; &nbsp; &nbsp; &nbsp; onUnmounted(() =&gt; {<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('unmounted!');<br /> &nbsp; &nbsp; &nbsp; &nbsp; });<br /> &nbsp; &nbsp; },<br /> };<br /> 一些思考<br /> 上面的详解部分,主要抽取的是 Vue Function API 的常见部分,并非RFC:Function-based component API的全部,例如其中的依赖注入,TypeScript类型推导等优势,在这里,由于篇幅有限,想要了解更多的朋友,可以点开RFC:Function-based component API查看。个人也在Function-based component API讨论区看到了更多地一些意见:<br /> <br /> 由于底层设计,在setup取不到组件实例this的问题,这个问题在笔者尝试体验时也遇到了,期待正式发布的 Vue 3.x 能够改进这个问题。<br /> <br /> 对于基本类型的值必须使用包装对象的问题:在 RFC 讨论区,为了同时保证TypeScript类型推导、复用性和保留Vue的数据监听,包装属性必须使用.value来取值是讨论最激烈的<br /> <br /> 关于包装对象value和state方法命名不清晰可能导致开发者误导等问题,已经在Amendment proposal to Function-based Component API这个提议中展开了讨论:<br /> <br /> setup() {<br /> &nbsp; &nbsp; const state = reactive({<br /> &nbsp; &nbsp; &nbsp; &nbsp; count: 0,<br /> &nbsp; &nbsp; });<br /> &nbsp;<br /> &nbsp; &nbsp; const double = computed(() =&gt; state.count * 2);<br /> &nbsp;<br /> &nbsp; &nbsp; function increment() {<br /> &nbsp; &nbsp; &nbsp; &nbsp; state.count++;<br /> &nbsp; &nbsp; }<br /> &nbsp;<br /> &nbsp; &nbsp; return {<br /> &nbsp; &nbsp; &nbsp; &nbsp; ...toBindings(state), // retains reactivity on mutations made tostate`

        double,

        increment,

    };

}

 



引入reactive API 和 binding API,其中reactive API 类似于 state API , binding API 类似于 value API。

之前使用的方法名state在 Vue 2.x 中可能被用作组件状态对象,导致变量命名空间的冲突问题,团队认为将state API 更名为 reactive 更为优雅。开发者能够写出const state = ... ,然后通过state.xxxx这种方式来获取组件状态,这样也相对而言自然一些。

value方法用于封装基本类型时,确实会出现不够优雅的.value的情况,开发者可能会在直接对包装对象取值时忘记使用.value,修正方案提出的 reactive API,其含义是创建响应式对象,初始化状态state就使用reactive创建,可保留每项属性的getter和setter,这么做既满足类型推导,也可以保留响应式引用,从而可在不同模块中共享状态值的引用。

但reactive可能导致下面的问题,需要引入binding API。 解决,如使用reactive创建的响应式对象,对其使用拓展运算符...时,则会丢失对象的getter和setter,提供toBindings方法能够保留状态的响应式。

当然,目前 Vue Function API 还处在讨论阶段,Vue 3.0 还处在开发阶段,还是期待下半年 Vue 3.0 的初版问世吧,希望能给我们带来更多的惊喜。


Vue cli之全家桶搭建项目

seo达人

一、搭建cli

1.事先安装好cnpm(淘宝镜像)



npm install -g cnpm --registry=https://registry.npm.taobao.org

1

2.cnpm install -g vue-cli



全局安装vue脚手架工具。(下载一次就好)



3.vue init webpack your_project_name



创建一个脚手架项目(每次创建需要)



eg:这时在命令行中有需要你填的信息{

你的项目名;

你的项目描述;

还有你想是否下载的插件(y/n);

}



4.使用 npm run dev来运行项目



就这样,一个简单的vue开发项目模板就这样下载完成了。



eg:

i 是install 的简写。

全局安装依赖:



cnpm i   依赖名

1

局部安装依赖:



cnpm i -D  依赖名

1

二、vue-router

一般事先安装模板时,已经安装上了。

可以查看package.json中。

如果没有安装



cnpm i -D vue-router

1

安装好之后,在src目录中会生成一个router目录,里面放着index.js,

一般有两种配置

第一种:



import Vue from 'vue';

import Router from 'vue-router';

Vue.use(Router);

export default new Router({

    routes: [

// 一进入就显示页面

        {

            path: '/',

            redirect: '/index'

        },

        {

            path: '/',

            component: pather => require(['../components/common/bodys.vue'], pather),

            meta: { title: '主体' },

            children:[

                {

                    path: '/index',

                    component: pather => require(['../components/page/index.vue'], pather),

                    meta: { title: '系统首页' }

                },

                {

                    path: '/biaoge',

                    component: pather => require(['../components/page/biaoge.vue'], pather),

                    meta: { title: '基础表格' }

                },

                {

                    path: '/Tab',

                    component: pather => require(['../components/page/Tab.vue'], pather),

                    meta: { title: 'tab选项卡' }

                },

                {

                    path: '/jibenbiaodan',

                    component: pather => require(['../components/page/jibenbiaodan.vue'], pather),

                    meta: { title: '基本表单' }

                },

                {

                    path: '/fuwenben',

                    component: pather => require(['../components/page/fuwenben.vue'], pather),

                    meta: { title: '富文本编辑器' }

                },

                {

                    path: '/bianjiqi',

                    component: pather => require(['../components/page/bianjiqi.vue'], pather),

                    meta: { title: 'markdown编辑器' }    

                },

                {

                    path: '/shangchuan',

                    component: pather => require(['../components/page/shangchuan.vue'], pather),

                    meta: { title: '文件上传' }   

                },

                {

                    path: '/scharts',

                    component: pather => require(['../components/page/scharts.vue'], pather),

                    meta: { title: 'schart图表' }

                },

                {

                    path: '/tuozhuai',

                    component: pather => require(['../components/page/tuozhuai.vue'], pather),

                    meta: { title: '拖拽列表' }

                },

                {

                    path: '/quanxianceshi',

                    component: pather => require(['../components/page/quanxianceshi.vue'], pather),

                    meta: { title: '权限测试', permission: true }

                }             

            ]

        },

        {

            path: '/login',

            component: pather => require(['../components/page/login.vue'], pather)

        },



        {

            path: '/cuowu404',

            component: pather => require(['../components/page/cuowu404.vue'], pather)

        },

        {

            path: '/cuowu403',

            component: pather => require(['../components/page/cuowu403.vue'], pather)

        },

        {

            path: '*',

            redirect: '/404'

        }

    ],

// 去掉#号

mode:"history"

})





第二种:



import Vue from 'vue'

import Router from 'vue-router'

import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)



export default new Router({

  routes: [

    {

      path: '/',

      name: 'HelloWorld',

      component: HelloWorld

    }

  ]

})



三、axios

先安装



cnpm i -D axios

1

然后在main.js写入



import axios from 'axios'



Vue.prototype.$axios = axios

1

2

3

这样就可以在组件中使用axios 获取数据了



    loadData(){

            this.$axios.get(['https://free-api.heweather.com/v5/weather?city=qingdao&amp;key=1b47b16e4aa545eaa55a66f859ac0089'])

                .then((response) => {

                    // success

                    console.log(response.data);

                })

                .catch((error) => {

                    //error

                    console.log(error);

                })

        },



四、vuex

1、安装



cnpm i -D vuex

1

2、然后需要手动创建一个文件夹store在src目录当中,

接着在store文件夹中创建store.js

例:



import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)



export default new Vuex.Store({

  state: {

    count: 0

  },

  mutations: {

    increment: state => state.count++,

    decrement: state => state.count--,

  }

})

1

2

3

4

5

6

7

8

9

10

11

12

13

3、然后在main.js引入注册



import Vuex from 'vuex'

import store from './store/store'



Vue.use(Vuex)



new Vue({

  el: '#app',

  router,

  store,

  components: { App },

  template: '<App/>'

})



比如在headers.vue使用vuex



<template>

    <div class="headers">

     <p>{{count}}</p>

     <button @click="increment">+</button>

     <button @click="decrement">-</button>

    </div>

</template>

<script>

import { mapState } from 'vuex'

export default {

  name: 'headers',

  data () {

    return {

      msg: 'Welcome to Your Vue.js App'

    }

  },

  methods: {

        increment(){

          this.$store.commit('increment')

        },

        decrement(){

          this.$store.commit('decrement')

        }

  },

    computed:{

        count(){

            return this.$store.state.count

        },

    }



}

</script>

<style scoped lang="scss" >

</style>





五、sass

1、需要安装sass

(1)安装node-sass

(2)安装sass-loader

(3)安装style-loader 有些人安装的是 vue-style-loader 其实是一样的!



cnpm install node-sass --save-dev 

cnpm install sass-loader --save-dev  

cnpm install style-loader --save-dev

1

2

3

2、接着需要更改build文件夹下面的webpack.base.config.js



'use strict'

const path = require('path')

const utils = require('./utils')

const config = require('../config')

const vueLoaderConfig = require('./vue-loader.conf')



function resolve (dir) {

  return path.join(dirname, '..', dir)

}







module.exports = {

  context: path.resolve(
dirname, '../'),

  entry: {

    app: './src/main.js'

  },

  output: {

    path: config.build.assetsRoot,

    filename: '[name].js',

    publicPath: process.env.NODE_ENV === 'production'

      ? config.build.assetsPublicPath

      : config.dev.assetsPublicPath

  },

  resolve: {

    extensions: ['.js', '.vue', '.json'],

    alias: {

      'vue$': 'vue/dist/vue.esm.js',

      '@': resolve('src'),

    }

  },

  module: {

    rules: [

      {

        test: /.vue$/,

        loader: 'vue-loader',

        options: vueLoaderConfig

      },

      {

        test: /.js$/,

        loader: 'babel-loader',

        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]

      },

      {

        test: /.(png|jpe?g|gif|svg)(\?.)?$/,

        loader: 'url-loader',

        options: {

          limit: 10000,

          name: utils.assetsPath('img/[name].[hash:7].[ext]')

        }

      },

      {

        test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.
)?$/,

        loader: 'url-loader',

        options: {

          limit: 10000,

          name: utils.assetsPath('media/[name].[hash:7].[ext]')

        }

      },

      {

        test: /.(woff2?|eot|ttf|otf)(\?.*)?$/,

        loader: 'url-loader',

        options: {

          limit: 10000,

          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')

        }

      },

      { //从这一段上面是默认的!不用改!下面是没有的需要你手动添加,相当于是编译识别sass! 

        test: /.scss$/,

        loaders: ["style", "css", "sass"]

      }

    ]

  },

  node: {

    // prevent webpack from injecting useless setImmediate polyfill because Vue

    // source contains it (although only uses it if it's native).

    setImmediate: false,

    // prevent webpack from injecting mocks to Node native modules

    // that does not make sense for the client

    dgram: 'empty',

    fs: 'empty',

    net: 'empty',

    tls: 'empty',

    child_process: 'empty'

  }

}





3、在你需要使用sass的地方写入即可



 <style lang="scss" scoped="" type="text/css"> 

 $primary-color: #333; 

   body {

        color: $primary-color;

       } 

</style>



六、vue UI库

这里已著名的Element组件库为例

https://element.eleme.cn/#/zh-CN/component/carousel



1、安装



npm i element-ui -S

1

2、使用

在main.js写入



import ElementUI from 'element-ui'

import 'element-ui/lib/theme-chalk/index.css'



Vue.use(ElementUI)

1

2

3

4

3、然后在组件使用就可以了

例:轮播图



<template>

  <el-carousel indicator-position="outside">

    <el-carousel-item v-for="item in 4" :key="item">

      <h3>{{ item }}</h3>

    </el-carousel-item>

  </el-carousel>

</template>



<style>

  .el-carouselitem h3 {

    color: #475669;

    font-size: 18px;

    opacity: 0.75;

    line-height: 300px;

    margin: 0;

  }

  

  .el-carousel
item:nth-child(2n) {

    background-color: #99a9bf;

  }

  

  .el-carousel__item:nth-child(2n+1) {

    background-color: #d3dce6;

  }

</style>

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

vue 移动端弹出键盘导致页面fixed布局错乱

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

话不多说,直接上问题图片


这里确认按钮是fixed布局 bottom:0 弹出键盘之后按钮被顶到了键盘上面

网上搜到的解决方案有两种,

一种是监听页面高度(我采用的这种)

一种是监听软键盘事件(ios和安卓实现方式不同,未采用)

下面是实现代码

data() {
    return {
        docmHeight: document.documentElement.clientHeight ||document.body.clientHeight,
        showHeight: document.documentElement.clientHeight ||document.body.clientHeight,
        hideshow:true  //显示或者隐藏footer
    }
  },
watch: {
        //监听显示高度
      showHeight:function() {
          if(this.docmHeight > this.showHeight){
            //隐藏
              this.hideshow=false
          }else{
            //显示
              this.hideshow=true
          }
      }
  },
mounted() {
      //监听事件
      window.onresize = ()=>{
          return(()=>{
              this.showHeight = document.documentElement.clientHeight || document.body.clientHeight;
      })()
      }
 
  },
<div class="bottom" v-show="hideshow">
    <div class="btn">
      确认操作
    </div>
  </div>
我这里使用的是方法是:当键盘弹出时,将按钮隐藏。如果必须出现按钮的话,可以修改按钮回归到正常的流中。
蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、网站建设 平面设计服务

Vue 插槽之 作用域插槽

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

现在我有如下需求,子组件 <user /> 中此时有一条用户的信息(userInfo);我要在父组件通过插槽展示这个用户的姓名(userInfo.name);

注意:这里的父组件并没有这个用户的信息,子组件中有,如果直接在父组件{{userInfo.name}} 获取这条信息是获取不到的;因为,只有 <user /> 组件可以访问到 userInfo,而我们提供的内容是在父组件渲染的;
模板在哪写,就是用哪里的变量,跟插槽用在哪无关
模板是在父组件中写好,被编译过后,传到子组件的插槽中的

为了让父组件的插槽内容可以读取到子组件的数据,我们可以将userInfo 作为一个 <slot> 元素的特性绑定上去;

// 子组件
const card = {
    data() {
        return {
            userInfo: {name: '宫鑫'}
        }
    },
    template: `
    <div class='card'>
        <!-- 在插槽上绑定子组件的数据 -->
        <slot :userInfo="userInfo"/>
    </div>
    `
};

绑定在 元素上的特性被称为插槽 prop。现在在父级作用域中,我们可以给v-slot带一个值来定义我们提供的插槽 prop 的名字:

// 父组件
template: `
<div>
    <card>
        <template v-slot:default="userInfo">
            用户姓名: {{userInfo}}
        </template>
    </card>
</div>
`

// 输出:
// 用户姓名: { "userInfo": { "name": "宫鑫" } }

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

Vue 全局变量,局部变量

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

全局组件和局部组件
* 1.先定义组件   Vue.component('组件名', { 组件模板对象 })
*   注意: 组件名不要使用原生的标签名, 若组件名定义时用的是驼峰命名法, 则调用时用中划线分割后小写
*                       例如: 组件-->mtText   使用时-->   <my-text></my-text>
* 2.配置组件的模板  注意: 组件的模板内容有且只有一个根元素
* 3.在视图层里调用 ,用双标签
* 4.组件是一个独立的作用域, 也可以看成一个特殊的vue实例, 可以有data, methods,computed等等
*   注意: 组件的data是函数, 函数中需要返回一个对象作为组件的data
全局组件案例

<body>
<div id="app">
    <my-component></my-component>
</div>
<script src="lib/vue-2.4.0.js"></script>
<script>
//全局组件
    Vue.component('myComponent',{
        //1.组件的内容/模板
        template: '<div><div>头部组件</div><h1 @click="fn">呵呵{{msg}}</h1></div>',
        data(){
            return {
                msg:'hello,组件'
            }
        },
        methods:{
            fn(){
                console.log(this.msg);
            }
        }
    })
    let vm = new Vue({
        el:"#app",
        data:{
        },
        methods:{

        },

    })
</script>
</body>
局部组件案例

<body>
<div id="app">
    <my-component></my-component>
    <my-test></my-test>
</div>
<template id="box1">
    <h1>haha</h1>
</template>
<template id="box2">
    <div>
        <ul>
            <li v-for="item in arr">
                {{ item }}
            </li>
        </ul>
    </div>
</template>
<script src="lib/vue-2.4.0.js"></script>
<script>
let vm = new Vue({
        el:"#app",
        data:{
        },
        methods:{

        },
        //局部子组件
        components:{
            // 组件名: {配置项}
            "myComponent":{
                template:'#box1',
                data(){
                    return {
                        msg:"哈哈"
                    }
                }
            },
            "myTest":{
                template:"#box2",
                data(){
                    return {
                        arr:[1,2,3,4]
                    }
                }
            }
        }
    })
</script>
</body>
组件切换:法一

<body>
<div id="app">
    <a href="" @click.prevent="flag=true">登录</a>
    <a href="" @click.prevent="flag=false">注册</a>
    <login v-if="flag"></login>
    <register v-else="flag"></register>
</div>
<script src="lib/vue-2.4.0.js"></script>
<script>
    Vue.component("login",{
        template:"<h1>登录组件</h1>"
    })
    Vue.component("register",{
        template:"<h1>注册组件</h1>"
    })
    let vm = new Vue({
        el:"#app",
        data:{
            flag: false
        },
        methods:{
        },
    })
</script>
</body>
组件切换:法二

 <style>
        .red{
            color:red;
        }
        .v-enter{
            opacity:0;
            transform: translateX(150px);
        }
        .v-leave-to{
            opacity:0;
            transform: translateX(-150px);
        }
        .v-enter-active,
        .v-leave-active{
            transition: all 0.5s;
            position: absolute;
        }
    </style>
</head>
<body>
<div id="app">
    <a href="" :class="{red: flag=='login'}" @click.prevent="flag='login'">登录</a>
    <a href="" :class="{red: flag=='register'}" @click.prevent="flag='register'">注册</a>
    <!--  vue提供了一个标签  component标签(理解为一个占位符), 用来展示对应名称的组件  :is属性设置指定的组件名  -->
    <transition>
        <component :is="flag"></component>
    </transition>
</div>
<script src="lib/vue-2.4.0.js"></script>
<script>
    Vue.component("login",{
        template:"<h1>登录组件</h1>"
    })
    Vue.component("register",{
        template:"<h1>注册组件</h1>"
    })
    let vm = new Vue({
        el:"#app",
        data:{
            flag: "login"
        },
        methods:{

        },
    })
</script>
</body>
父组件向子组件传值

<body>
<div id="app">
    <my-component :fromfather="father"></my-component>
</div>
<template id="box1">
    <h1 @click="change">
        {{ fromfather }}
        子组件的数据
    </h1>
</template>
<template id="grandSon">
    <h1>孙子组件的数据</h1>
</template>
<!--1.子组件不能访问父组件的数据
2. 解决办法: ①在引用子组件时, 通过属性绑定 v-bind方法, 把需要传递给子组件的数据以绑定的形式传过来
              ② 在子组件配置项里添加 props: ['传递过来的数据']-->
<script src="lib/vue-2.4.0.js"></script>
<script>
    let vm = new Vue({
        el:"#app",
        data:{
            father:'啊~~这是父组件的数据'
        },
        methods:{
        },
        //局部子组件
        components:{
            // 组件名: {配置项}
            "myComponent":{
                template:'#box1',
                data(){
                    return {
                        msg:"哈哈"
                    }
                },
                //在子组件配置项里添加 props: ['传递过来的数据']
                //注意: 组件中所有的props中的数据, 都是通过父组件传递给子组件的, props中的数据是只读, 无法修改
                props:['fromfather'],
                methods:{
                    change(){
                       // this.fromfather = "被修改了"
                    }
                },
                //局部子子组件
                components:{
                    'grandSon':{
                        template:'#grandSon'
                    }
                }
            }
        }
    })
</script>
</body>
蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

VUE,创建组件的方式

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

方式一

 <!--1.1使用Vue.extend来创建全局的Vue组件--> var tem1 = Vue.extend({
      template:'<h3>这是使用 Vue.extend 创建的组件</h3>' //指定组件要展示的HTML结构
    }); <!--1.2使用Vue.component('组件名称',创建出来的组件模板对象)--> Vue.component('myTem1',tem1);

    /* <!--注意--> 使用 Vue.component() 定义全局组件的时候,
        组件名称使用 驼峰命名,则在引用组件的时候,需要把大写改为小写,并且用 '-'将单词连接
        组件名称不适用驼峰命名,则直接拿名称来使用即可
     */ <!--组合方式--> Vue.component('myTem1',Vue.extend({
        template : '<h3>这是使用 Vue.extend 创建的组件</h3>'
    })) <div id="app"> <!-- 如果要使用组件,直接把组件的名称以 HTML 标签的形式,引入到页面中--> <my-tem1> </my-tem1> </div> 
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

方式二

直接使用Vue.component()

 Vue.component('mycom2',{
        template : '<h3>这是使用 Vue.component 创建的组件</h3>' }) 
    
  • 1
  • 2
  • 3

但是这样写会有一个问题:

<!--在h3标签后紧接一个span标签的话就会出问题了--> <h3>这是使用 Vue.component 创建的组件</h3> <span>123</span> 
    
  • 1
  • 2


这个问题是在 组件template属性指向的模板内容,必须有且只能有唯一的一个根元素 
所以修改代码如下:

Vue.component('mycom2',{
        template : 
            '<div> <h3>这是使用 Vue.component 创建的组件</h3> <span>123</span> </div>'
}) 
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

运行结果如下:

这里写图片描述

不过这种方式也有一个瑕疵,就是template 属性的值是HTML标签,而在软件中,并没有智能提示,容易出错,若使用这种方式,需要仔细,避免出错

方式三

<!--1.定义组件:--> Vue.component('mycom3',{
            template : '#tem1'
     }); <!--2.在被控制的 #app 外面使用 template 元素,定义组建的HTML模板结构--> <div id="app"> <!--3. 引用组件 --> <mycom3></mycom3> </div> <template id="tem1"> <div> <h1>这是 template 元素</h1> <span>这种方式好用</span> </div> </template>  
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

运行结果如下:

这里写图片描述

这是Vue创建组件(全局)的3种方式,其实相差不多,希望对大家有所帮助


VUE 学习总结之简单的Rate评分组件

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

说明

本组件基于element-ui 的图标库(星星图标)

第一步:

vue + webpack + element-ui 框架

第二步:

创建Rate.vue文件,实现双向绑定分数

第三部:

使用组件

代码

在app.vue中引入组件


    
  1. <Rate v-model='value' size="32px">
  2. <span>{{value}} 分</span>
  3. </Rate>
import Rate from './components/Rate'

组件


    
  1. <template>
  2. <div class="Rating" :value='value'>
  3. <ul class="Rating-list">
  4. <li v-for="s in 5" @click="changeRate(s)">
  5. <i :class="s <= star ? 'el-icon-star-on':'el-icon-star-off'" :style='style'></i>
  6. </li>
  7. </ul>
  8. <slot></slot> <!--显示用户自定义内容-->
  9. </div>
  10. </template>


    
  1. props: {
  2. size: { //父组件传值设置字体大小
  3. type: String,
  4. default: '16px'
  5. },
  6. value: { //绑定value,与$emit实现双向绑定
  7. type:Number,
  8. default:0
  9. }
  10. },
  11. data() {
  12. return {
  13. star: this.value, // 初始化
  14. style: {
  15. fontSize: this.size //通过prop传值设置星星字体大小
  16. }
  17. }
  18. },
  19. methods: {
  20. changeRate(s) {
  21. this.star = s //更新当前星星数量
  22. this.$emit('input', s); //将当前星星数量s与v-model绑定
  23. }
  24. }

demo演示



日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档